Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(165)

Unified Diff: ports/python_modules/pyzmq/nacl.patch

Issue 138913004: Build system for statically-linked Python. (Closed) Base URL: https://naclports.googlecode.com/svn/trunk/src
Patch Set: Final update with merge against current naclports.py Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « ports/python_modules/pyzmq/modules.list ('k') | ports/python_modules/pyzmq/pkg_info » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ports/python_modules/pyzmq/nacl.patch
===================================================================
new file mode 100644
--- /dev/null
+++ b/ports/python_modules/pyzmq/nacl.patch
@@ -0,0 +1,5159 @@
+diff --git a/buildutils/config.py b/buildutils/config.py
+index 66f61e3..de2cd6e 100644
+--- a/buildutils/config.py
++++ b/buildutils/config.py
+@@ -87,6 +87,11 @@ def get_cfg_args():
+ cfg = cfg2dict(cfg)
+
+ g = cfg.setdefault('global', {})
++ if "NACL_BUILD_TREE" in os.environ:
++ NACL_TREE = os.environ["NACL_BUILD_TREE"]
++ cfg["global"]["zmq_prefix"] = NACL_TREE
++ cfg["global"]["have_sys_un_h"] = "False"
++
+ # boolean keys:
+ for key in ['libzmq_extension',
+ 'bundle_libzmq_dylib',
+diff --git a/setup.cfg b/setup.cfg
+new file mode 100644
+index 0000000..15686fc
+--- /dev/null
++++ b/setup.cfg
+@@ -0,0 +1,3 @@
++[bdist_egg]
++plat-name = pnacl
++
+diff --git a/setup.py b/setup.py
+index 5348c61..a204e23 100755
+--- a/setup.py
++++ b/setup.py
+@@ -270,6 +270,10 @@ class Configure(build_ext):
+ # include internal directories
+ settings.setdefault('include_dirs', [])
+ settings['include_dirs'] += [pjoin('zmq', sub) for sub in ('utils','core','devices')]
++ if "NACL_BUILD_TREE" in os.environ:
++ settings['include_dirs'].append(pjoin(
++ os.environ["NACL_BUILD_TREE"],
++ "include", "glibc-compat"))
+
+ for ext in self.distribution.ext_modules:
+ if ext.name == 'zmq.libzmq':
+@@ -826,29 +830,29 @@ def dotc(subdir, name):
+
+ libzmq = pxd('core', 'libzmq')
+ buffers = pxd('utils', 'buffers')
+-message = pxd('core', 'message')
+-context = pxd('core', 'context')
+-socket = pxd('core', 'socket')
++message = pxd('core', '_zmessage')
++context = pxd('core', '_zcontext')
++socket = pxd('core', '_zsocket')
+ checkrc = pxd('core', 'checkrc')
+-monqueue = pxd('devices', 'monitoredqueue')
++monqueue = pxd('devices', '_zmonitoredqueue')
+
+ submodules = dict(
+- core = {'constants': [libzmq],
+- 'error':[libzmq, checkrc],
+- '_poll':[libzmq, socket, context, checkrc],
+- 'stopwatch':[libzmq, pxd('core','stopwatch'), checkrc],
+- 'context':[context, libzmq, checkrc],
+- 'message':[libzmq, buffers, message, checkrc],
+- 'socket':[context, message, socket, libzmq, buffers, checkrc],
+- '_device':[libzmq, socket, context, checkrc],
+- '_version':[libzmq],
++ core = {'_zconstants': [libzmq],
++ '_zerror':[libzmq, checkrc],
++ '__zpoll':[libzmq, socket, context, checkrc],
++ '_zstopwatch':[libzmq, pxd('core','_zstopwatch'), checkrc],
++ '_zcontext':[context, libzmq, checkrc],
++ '_zmessage':[libzmq, buffers, message, checkrc],
++ '_zsocket':[context, message, socket, libzmq, buffers, checkrc],
++ '__zdevice':[libzmq, socket, context, checkrc],
++ '__zversion':[libzmq],
+ },
+ devices = {
+- 'monitoredqueue':[buffers, libzmq, monqueue, socket, context, checkrc],
++ '_zmonitoredqueue':[buffers, libzmq, monqueue, socket, context, checkrc],
+ },
+ utils = {
+- 'initthreads':[libzmq],
+- 'rebuffer':[buffers],
++ '_zinitthreads':[libzmq],
++ '_zrebuffer':[buffers],
+ },
+ )
+
+ #-----------------------------------------------------------------------------
+ # Main setup
+ #-----------------------------------------------------------------------------
+diff --git a/zmq/__init__.py b/zmq/__init__.py
+index 19cb4a9..c55ac5c 100644
+--- a/zmq/__init__.py
++++ b/zmq/__init__.py
+@@ -39,7 +39,7 @@ if bundled:
+
+ if 'PyPy' not in sys.version:
+ try:
+- from zmq.utils import initthreads # initialize threads
++ from zmq.utils import _zinitthreads as initthreads # initialize threads
+ except ImportError as e:
+ raise ImportError("%s\nAre you trying to `import zmq` from the pyzmq source dir?" % e)
+ else:
+diff --git a/zmq/core/__init__.py b/zmq/core/__init__.py
+index 862f1d5..275e47a 100644
+--- a/zmq/core/__init__.py
++++ b/zmq/core/__init__.py
+@@ -23,21 +23,21 @@
+ # Imports
+ #-----------------------------------------------------------------------------
+
+-from zmq.core import (constants, error, message, context,
+- socket, stopwatch, _poll, _version, _device )
++from zmq.core import (_zconstants, _zerror, _zmessage, _zcontext,
++ _zsocket, _zstopwatch, __zpoll, __zversion, __zdevice )
+
+ __all__ = []
+-for submod in (constants, error, message, context,
+- socket, stopwatch, _poll, _version, _device):
++for submod in (_zconstants, _zerror, _zmessage, _zcontext,
++ _zsocket, _zstopwatch, __zpoll, __zversion, __zdevice):
+ __all__.extend(submod.__all__)
+
+-from zmq.core.constants import *
+-from zmq.core.error import *
+-from zmq.core.message import *
+-from zmq.core.context import *
+-from zmq.core.socket import *
+-from zmq.core._poll import *
+-from zmq.core.stopwatch import *
+-from zmq.core._device import *
+-from zmq.core._version import *
++from zmq.core._zconstants import *
++from zmq.core._zerror import *
++from zmq.core._zmessage import *
++from zmq.core._zcontext import *
++from zmq.core._zsocket import *
++from zmq.core.__zpoll import *
++from zmq.core._zstopwatch import *
++from zmq.core.__zdevice import *
++from zmq.core.__zversion import *
+
+diff --git a/zmq/core/__zdevice.pyx b/zmq/core/__zdevice.pyx
+new file mode 100644
+index 0000000..99bcc27
+--- /dev/null
++++ b/zmq/core/__zdevice.pyx
+@@ -0,0 +1,86 @@
++"""Python binding for 0MQ device function."""
++
++#
++# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
++#
++# This file is part of pyzmq.
++#
++# pyzmq is free software; you can redistribute it and/or modify it under
++# the terms of the Lesser GNU General Public License as published by
++# the Free Software Foundation; either version 3 of the License, or
++# (at your option) any later version.
++#
++# pyzmq is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++# Lesser GNU General Public License for more details.
++#
++# You should have received a copy of the Lesser GNU General Public License
++# along with this program. If not, see <http://www.gnu.org/licenses/>.
++#
++
++#-----------------------------------------------------------------------------
++# Imports
++#-----------------------------------------------------------------------------
++
++from libzmq cimport zmq_device, zmq_proxy, ZMQ_VERSION_MAJOR
++from zmq.core._zsocket cimport Socket as cSocket
++from zmq.core.checkrc cimport _check_rc
++
++#-----------------------------------------------------------------------------
++# Basic device API
++#-----------------------------------------------------------------------------
++
++def device(int device_type, cSocket frontend, cSocket backend=None):
++ """device(device_type, frontend, backend)
++
++ Start a zeromq device.
++
++ WARNING: zmq.device is deprecated as of libzmq-3.2,
++ in favor of zmq.proxy.
++
++ Parameters
++ ----------
++ device_type : (QUEUE, FORWARDER, STREAMER)
++ The type of device to start.
++ frontend : Socket
++ The Socket instance for the incoming traffic.
++ backend : Socket
++ The Socket instance for the outbound traffic.
++ """
++ if ZMQ_VERSION_MAJOR >= 3:
++ return proxy(frontend, backend)
++
++ cdef int rc = 0
++ with nogil:
++ rc = zmq_device(device_type, frontend.handle, backend.handle)
++ _check_rc(rc)
++ return rc
++
++def proxy(cSocket frontend, cSocket backend, cSocket capture=None):
++ """proxy(frontend, backend, capture)
++
++ Start a zeromq proxy (replacement for device).
++
++ Parameters
++ ----------
++ frontend : Socket
++ The Socket instance for the incoming traffic.
++ backend : Socket
++ The Socket instance for the outbound traffic.
++ capture : Socket
++ The Socket instance for capturing traffic.
++ """
++ cdef int rc = 0
++ cdef void* capture_handle
++ if isinstance(capture, cSocket):
++ capture_handle = capture.handle
++ else:
++ capture_handle = NULL
++ with nogil:
++ rc = zmq_proxy(frontend.handle, backend.handle, capture_handle)
++ _check_rc(rc)
++ return rc
++
++__all__ = ['device', 'proxy']
++
+diff --git a/zmq/core/__zpoll.pyx b/zmq/core/__zpoll.pyx
+new file mode 100644
+index 0000000..799b20b
+--- /dev/null
++++ b/zmq/core/__zpoll.pyx
+@@ -0,0 +1,136 @@
++"""0MQ polling related functions and classes."""
++
++#
++# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
++#
++# This file is part of pyzmq.
++#
++# pyzmq is free software; you can redistribute it and/or modify it under
++# the terms of the Lesser GNU General Public License as published by
++# the Free Software Foundation; either version 3 of the License, or
++# (at your option) any later version.
++#
++# pyzmq is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++# Lesser GNU General Public License for more details.
++#
++# You should have received a copy of the Lesser GNU General Public License
++# along with this program. If not, see <http://www.gnu.org/licenses/>.
++#
++
++#-----------------------------------------------------------------------------
++# Imports
++#-----------------------------------------------------------------------------
++
++from libc.stdlib cimport free, malloc
++
++from libzmq cimport zmq_pollitem_t, ZMQ_VERSION_MAJOR
++from libzmq cimport zmq_poll as zmq_poll_c
++from _zsocket cimport Socket
++
++import sys
++
++from zmq.core.checkrc cimport _check_rc
++
++#-----------------------------------------------------------------------------
++# Polling related methods
++#-----------------------------------------------------------------------------
++
++# version-independent typecheck for int/long
++if sys.version_info[0] >= 3:
++ int_t = int
++else:
++ int_t = (int,long)
++
++def zmq_poll(sockets, long timeout=-1):
++ """zmq_poll(sockets, timeout=-1)
++
++ Poll a set of 0MQ sockets, native file descs. or sockets.
++
++ Parameters
++ ----------
++ sockets : list of tuples of (socket, flags)
++ Each element of this list is a two-tuple containing a socket
++ and a flags. The socket may be a 0MQ socket or any object with
++ a ``fileno()`` method. The flags can be zmq.POLLIN (for detecting
++ for incoming messages), zmq.POLLOUT (for detecting that send is OK)
++ or zmq.POLLIN|zmq.POLLOUT for detecting both.
++ timeout : int
++ The number of milliseconds to poll for. Negative means no timeout.
++ """
++ cdef int rc, i
++ cdef zmq_pollitem_t *pollitems = NULL
++ cdef int nsockets = <int>len(sockets)
++ cdef Socket current_socket
++
++ if nsockets == 0:
++ return []
++
++ pollitems = <zmq_pollitem_t *>malloc(nsockets*sizeof(zmq_pollitem_t))
++ if pollitems == NULL:
++ raise MemoryError("Could not allocate poll items")
++
++ if ZMQ_VERSION_MAJOR < 3:
++ # timeout is us in 2.x, ms in 3.x
++ # expected input is ms (matches 3.x)
++ timeout = 1000*timeout
++
++ for i in range(nsockets):
++ s = sockets[i][0]
++ events = sockets[i][1]
++ if isinstance(s, Socket):
++ current_socket = s
++ pollitems[i].socket = current_socket.handle
++ pollitems[i].events = events
++ pollitems[i].revents = 0
++ elif isinstance(s, int_t):
++ pollitems[i].socket = NULL
++ pollitems[i].fd = s
++ pollitems[i].events = events
++ pollitems[i].revents = 0
++ elif hasattr(s, 'fileno'):
++ try:
++ fileno = int(s.fileno())
++ except:
++ free(pollitems)
++ raise ValueError('fileno() must return an valid integer fd')
++ else:
++ pollitems[i].socket = NULL
++ pollitems[i].fd = fileno
++ pollitems[i].events = events
++ pollitems[i].revents = 0
++ else:
++ free(pollitems)
++ raise TypeError(
++ "Socket must be a 0MQ socket, an integer fd or have "
++ "a fileno() method: %r" % s
++ )
++
++
++ with nogil:
++ rc = zmq_poll_c(pollitems, nsockets, timeout)
++
++ if rc < 0:
++ free(pollitems)
++ _check_rc(rc)
++
++ results = []
++ for i in range(nsockets):
++ s = sockets[i][0]
++ # Return the fd for sockets, for compat. with select.poll.
++ if hasattr(s, 'fileno'):
++ s = s.fileno()
++ revents = pollitems[i].revents
++ # Only return sockets with non-zero status for compat. with select.poll.
++ if revents > 0:
++ results.append((s, revents))
++
++ free(pollitems)
++ return results
++
++#-----------------------------------------------------------------------------
++# Symbols to export
++#-----------------------------------------------------------------------------
++
++__all__ = [ 'zmq_poll' ]
+diff --git a/zmq/core/__zversion.pyx b/zmq/core/__zversion.pyx
+new file mode 100644
+index 0000000..02cf6fc
+--- /dev/null
++++ b/zmq/core/__zversion.pyx
+@@ -0,0 +1,43 @@
++"""PyZMQ and 0MQ version functions."""
++
++#
++# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
++#
++# This file is part of pyzmq.
++#
++# pyzmq is free software; you can redistribute it and/or modify it under
++# the terms of the Lesser GNU General Public License as published by
++# the Free Software Foundation; either version 3 of the License, or
++# (at your option) any later version.
++#
++# pyzmq is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++# Lesser GNU General Public License for more details.
++#
++# You should have received a copy of the Lesser GNU General Public License
++# along with this program. If not, see <http://www.gnu.org/licenses/>.
++#
++
++#-----------------------------------------------------------------------------
++# Imports
++#-----------------------------------------------------------------------------
++
++from libzmq cimport _zmq_version
++
++#-----------------------------------------------------------------------------
++# Code
++#-----------------------------------------------------------------------------
++
++def zmq_version_info():
++ """zmq_version_info()
++
++ Return the version of ZeroMQ itself as a 3-tuple of ints.
++ """
++ cdef int major, minor, patch
++ _zmq_version(&major, &minor, &patch)
++ return (major, minor, patch)
++
++
++__all__ = ['zmq_version_info']
++
+diff --git a/zmq/core/_device.pyx b/zmq/core/_device.pyx
+deleted file mode 100644
+index 5471e73..0000000
+--- a/zmq/core/_device.pyx
++++ /dev/null
+@@ -1,86 +0,0 @@
+-"""Python binding for 0MQ device function."""
+-
+-#
+-# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
+-#
+-# This file is part of pyzmq.
+-#
+-# pyzmq is free software; you can redistribute it and/or modify it under
+-# the terms of the Lesser GNU General Public License as published by
+-# the Free Software Foundation; either version 3 of the License, or
+-# (at your option) any later version.
+-#
+-# pyzmq is distributed in the hope that it will be useful,
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-# Lesser GNU General Public License for more details.
+-#
+-# You should have received a copy of the Lesser GNU General Public License
+-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+-#
+-
+-#-----------------------------------------------------------------------------
+-# Imports
+-#-----------------------------------------------------------------------------
+-
+-from libzmq cimport zmq_device, zmq_proxy, ZMQ_VERSION_MAJOR
+-from zmq.core.socket cimport Socket as cSocket
+-from zmq.core.checkrc cimport _check_rc
+-
+-#-----------------------------------------------------------------------------
+-# Basic device API
+-#-----------------------------------------------------------------------------
+-
+-def device(int device_type, cSocket frontend, cSocket backend=None):
+- """device(device_type, frontend, backend)
+-
+- Start a zeromq device.
+-
+- WARNING: zmq.device is deprecated as of libzmq-3.2,
+- in favor of zmq.proxy.
+-
+- Parameters
+- ----------
+- device_type : (QUEUE, FORWARDER, STREAMER)
+- The type of device to start.
+- frontend : Socket
+- The Socket instance for the incoming traffic.
+- backend : Socket
+- The Socket instance for the outbound traffic.
+- """
+- if ZMQ_VERSION_MAJOR >= 3:
+- return proxy(frontend, backend)
+-
+- cdef int rc = 0
+- with nogil:
+- rc = zmq_device(device_type, frontend.handle, backend.handle)
+- _check_rc(rc)
+- return rc
+-
+-def proxy(cSocket frontend, cSocket backend, cSocket capture=None):
+- """proxy(frontend, backend, capture)
+-
+- Start a zeromq proxy (replacement for device).
+-
+- Parameters
+- ----------
+- frontend : Socket
+- The Socket instance for the incoming traffic.
+- backend : Socket
+- The Socket instance for the outbound traffic.
+- capture : Socket
+- The Socket instance for capturing traffic.
+- """
+- cdef int rc = 0
+- cdef void* capture_handle
+- if isinstance(capture, cSocket):
+- capture_handle = capture.handle
+- else:
+- capture_handle = NULL
+- with nogil:
+- rc = zmq_proxy(frontend.handle, backend.handle, capture_handle)
+- _check_rc(rc)
+- return rc
+-
+-__all__ = ['device', 'proxy']
+-
+diff --git a/zmq/core/_poll.pyx b/zmq/core/_poll.pyx
+deleted file mode 100644
+index 9db19e1..0000000
+--- a/zmq/core/_poll.pyx
++++ /dev/null
+@@ -1,136 +0,0 @@
+-"""0MQ polling related functions and classes."""
+-
+-#
+-# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
+-#
+-# This file is part of pyzmq.
+-#
+-# pyzmq is free software; you can redistribute it and/or modify it under
+-# the terms of the Lesser GNU General Public License as published by
+-# the Free Software Foundation; either version 3 of the License, or
+-# (at your option) any later version.
+-#
+-# pyzmq is distributed in the hope that it will be useful,
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-# Lesser GNU General Public License for more details.
+-#
+-# You should have received a copy of the Lesser GNU General Public License
+-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+-#
+-
+-#-----------------------------------------------------------------------------
+-# Imports
+-#-----------------------------------------------------------------------------
+-
+-from libc.stdlib cimport free, malloc
+-
+-from libzmq cimport zmq_pollitem_t, ZMQ_VERSION_MAJOR
+-from libzmq cimport zmq_poll as zmq_poll_c
+-from socket cimport Socket
+-
+-import sys
+-
+-from zmq.core.checkrc cimport _check_rc
+-
+-#-----------------------------------------------------------------------------
+-# Polling related methods
+-#-----------------------------------------------------------------------------
+-
+-# version-independent typecheck for int/long
+-if sys.version_info[0] >= 3:
+- int_t = int
+-else:
+- int_t = (int,long)
+-
+-def zmq_poll(sockets, long timeout=-1):
+- """zmq_poll(sockets, timeout=-1)
+-
+- Poll a set of 0MQ sockets, native file descs. or sockets.
+-
+- Parameters
+- ----------
+- sockets : list of tuples of (socket, flags)
+- Each element of this list is a two-tuple containing a socket
+- and a flags. The socket may be a 0MQ socket or any object with
+- a ``fileno()`` method. The flags can be zmq.POLLIN (for detecting
+- for incoming messages), zmq.POLLOUT (for detecting that send is OK)
+- or zmq.POLLIN|zmq.POLLOUT for detecting both.
+- timeout : int
+- The number of milliseconds to poll for. Negative means no timeout.
+- """
+- cdef int rc, i
+- cdef zmq_pollitem_t *pollitems = NULL
+- cdef int nsockets = <int>len(sockets)
+- cdef Socket current_socket
+-
+- if nsockets == 0:
+- return []
+-
+- pollitems = <zmq_pollitem_t *>malloc(nsockets*sizeof(zmq_pollitem_t))
+- if pollitems == NULL:
+- raise MemoryError("Could not allocate poll items")
+-
+- if ZMQ_VERSION_MAJOR < 3:
+- # timeout is us in 2.x, ms in 3.x
+- # expected input is ms (matches 3.x)
+- timeout = 1000*timeout
+-
+- for i in range(nsockets):
+- s = sockets[i][0]
+- events = sockets[i][1]
+- if isinstance(s, Socket):
+- current_socket = s
+- pollitems[i].socket = current_socket.handle
+- pollitems[i].events = events
+- pollitems[i].revents = 0
+- elif isinstance(s, int_t):
+- pollitems[i].socket = NULL
+- pollitems[i].fd = s
+- pollitems[i].events = events
+- pollitems[i].revents = 0
+- elif hasattr(s, 'fileno'):
+- try:
+- fileno = int(s.fileno())
+- except:
+- free(pollitems)
+- raise ValueError('fileno() must return an valid integer fd')
+- else:
+- pollitems[i].socket = NULL
+- pollitems[i].fd = fileno
+- pollitems[i].events = events
+- pollitems[i].revents = 0
+- else:
+- free(pollitems)
+- raise TypeError(
+- "Socket must be a 0MQ socket, an integer fd or have "
+- "a fileno() method: %r" % s
+- )
+-
+-
+- with nogil:
+- rc = zmq_poll_c(pollitems, nsockets, timeout)
+-
+- if rc < 0:
+- free(pollitems)
+- _check_rc(rc)
+-
+- results = []
+- for i in range(nsockets):
+- s = sockets[i][0]
+- # Return the fd for sockets, for compat. with select.poll.
+- if hasattr(s, 'fileno'):
+- s = s.fileno()
+- revents = pollitems[i].revents
+- # Only return sockets with non-zero status for compat. with select.poll.
+- if revents > 0:
+- results.append((s, revents))
+-
+- free(pollitems)
+- return results
+-
+-#-----------------------------------------------------------------------------
+-# Symbols to export
+-#-----------------------------------------------------------------------------
+-
+-__all__ = [ 'zmq_poll' ]
+diff --git a/zmq/core/_version.pyx b/zmq/core/_version.pyx
+deleted file mode 100644
+index 02cf6fc..0000000
+--- a/zmq/core/_version.pyx
++++ /dev/null
+@@ -1,43 +0,0 @@
+-"""PyZMQ and 0MQ version functions."""
+-
+-#
+-# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
+-#
+-# This file is part of pyzmq.
+-#
+-# pyzmq is free software; you can redistribute it and/or modify it under
+-# the terms of the Lesser GNU General Public License as published by
+-# the Free Software Foundation; either version 3 of the License, or
+-# (at your option) any later version.
+-#
+-# pyzmq is distributed in the hope that it will be useful,
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-# Lesser GNU General Public License for more details.
+-#
+-# You should have received a copy of the Lesser GNU General Public License
+-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+-#
+-
+-#-----------------------------------------------------------------------------
+-# Imports
+-#-----------------------------------------------------------------------------
+-
+-from libzmq cimport _zmq_version
+-
+-#-----------------------------------------------------------------------------
+-# Code
+-#-----------------------------------------------------------------------------
+-
+-def zmq_version_info():
+- """zmq_version_info()
+-
+- Return the version of ZeroMQ itself as a 3-tuple of ints.
+- """
+- cdef int major, minor, patch
+- _zmq_version(&major, &minor, &patch)
+- return (major, minor, patch)
+-
+-
+-__all__ = ['zmq_version_info']
+-
+diff --git a/zmq/core/_zconstants.pyx b/zmq/core/_zconstants.pyx
+new file mode 100644
+index 0000000..fa2695d
+--- /dev/null
++++ b/zmq/core/_zconstants.pyx
+@@ -0,0 +1,190 @@
++"""0MQ Constants."""
++
++#
++# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
++#
++# This file is part of pyzmq.
++#
++# pyzmq is free software; you can redistribute it and/or modify it under
++# the terms of the Lesser GNU General Public License as published by
++# the Free Software Foundation; either version 3 of the License, or
++# (at your option) any later version.
++#
++# pyzmq is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++# Lesser GNU General Public License for more details.
++#
++# You should have received a copy of the Lesser GNU General Public License
++# along with this program. If not, see <http://www.gnu.org/licenses/>.
++#
++
++#-----------------------------------------------------------------------------
++# Imports
++#-----------------------------------------------------------------------------
++
++from libzmq cimport *
++
++#-----------------------------------------------------------------------------
++# Python module level constants
++#-----------------------------------------------------------------------------
++
++_optionals = []
++
++if ZMQ_VERSION < 30000:
++ # backport DONTWAIT as alias to NOBLOCK
++ NOBLOCK = ZMQ_NOBLOCK
++ DONTWAIT = ZMQ_NOBLOCK
++else:
++ # keep NOBLOCK as alias for new DONTWAIT
++ NOBLOCK = ZMQ_DONTWAIT
++ DONTWAIT = ZMQ_DONTWAIT
++
++VERSION = ZMQ_VERSION
++
++# socket types
++PAIR = ZMQ_PAIR
++PUB = ZMQ_PUB
++SUB = ZMQ_SUB
++REQ = ZMQ_REQ
++REP = ZMQ_REP
++DEALER = ZMQ_DEALER
++ROUTER = ZMQ_ROUTER
++PULL = ZMQ_PULL
++PUSH = ZMQ_PUSH
++XPUB = ZMQ_XPUB
++XSUB = ZMQ_XSUB
++
++# keep deprecated aliases
++XREQ = DEALER
++XREP = ROUTER
++UPSTREAM = PULL
++DOWNSTREAM = PUSH
++
++
++# socket options
++AFFINITY = ZMQ_AFFINITY
++IDENTITY = ZMQ_IDENTITY
++SUBSCRIBE = ZMQ_SUBSCRIBE
++UNSUBSCRIBE = ZMQ_UNSUBSCRIBE
++RATE = ZMQ_RATE
++RECOVERY_IVL = ZMQ_RECOVERY_IVL
++RECONNECT_IVL_MAX = ZMQ_RECONNECT_IVL_MAX
++SNDBUF = ZMQ_SNDBUF
++RCVBUF = ZMQ_RCVBUF
++RCVMORE = ZMQ_RCVMORE
++SNDMORE = ZMQ_SNDMORE
++POLLIN = ZMQ_POLLIN
++POLLOUT = ZMQ_POLLOUT
++POLLERR = ZMQ_POLLERR
++
++STREAMER = ZMQ_STREAMER
++FORWARDER = ZMQ_FORWARDER
++QUEUE = ZMQ_QUEUE
++
++# sockopts new in 2.2.0
++SNDTIMEO = ZMQ_SNDTIMEO
++RCVTIMEO = ZMQ_RCVTIMEO
++
++# sockopts removed in 3.0.0
++HWM = ZMQ_HWM
++SWAP = ZMQ_SWAP
++MCAST_LOOP = ZMQ_MCAST_LOOP
++RECOVERY_IVL_MSEC = ZMQ_RECOVERY_IVL_MSEC
++
++# new in 3.x
++IO_THREADS = ZMQ_IO_THREADS
++MAX_SOCKETS = ZMQ_MAX_SOCKETS
++
++MORE = ZMQ_MORE
++
++MAXMSGSIZE = ZMQ_MAXMSGSIZE
++SNDHWM = ZMQ_SNDHWM
++RCVHWM = ZMQ_RCVHWM
++MULTICAST_HOPS = ZMQ_MULTICAST_HOPS
++IPV4ONLY = ZMQ_IPV4ONLY
++LAST_ENDPOINT = ZMQ_LAST_ENDPOINT
++
++ROUTER_MANDATORY = ZMQ_ROUTER_MANDATORY
++# aliases
++ROUTER_BEHAVIOR = ROUTER_MANDATORY
++FAIL_UNROUTABLE = ROUTER_MANDATORY
++
++TCP_KEEPALIVE = ZMQ_TCP_KEEPALIVE
++TCP_KEEPALIVE_CNT = ZMQ_TCP_KEEPALIVE_CNT
++TCP_KEEPALIVE_IDLE = ZMQ_TCP_KEEPALIVE_IDLE
++TCP_KEEPALIVE_INTVL = ZMQ_TCP_KEEPALIVE_INTVL
++TCP_ACCEPT_FILTER = ZMQ_TCP_ACCEPT_FILTER
++DELAY_ATTACH_ON_CONNECT = ZMQ_DELAY_ATTACH_ON_CONNECT
++XPUB_VERBOSE = ZMQ_XPUB_VERBOSE
++ROUTER_RAW = ZMQ_ROUTER_RAW
++
++EVENT_CONNECTED = ZMQ_EVENT_CONNECTED
++EVENT_CONNECT_DELAYED = ZMQ_EVENT_CONNECT_DELAYED
++EVENT_CONNECT_RETRIED = ZMQ_EVENT_CONNECT_RETRIED
++EVENT_LISTENING = ZMQ_EVENT_LISTENING
++EVENT_BIND_FAILED = ZMQ_EVENT_BIND_FAILED
++EVENT_ACCEPTED = ZMQ_EVENT_ACCEPTED
++EVENT_ACCEPT_FAILED = ZMQ_EVENT_ACCEPT_FAILED
++EVENT_CLOSED = ZMQ_EVENT_CLOSED
++EVENT_CLOSE_FAILED = ZMQ_EVENT_CLOSE_FAILED
++EVENT_DISCONNECTED = ZMQ_EVENT_DISCONNECTED
++
++FD = ZMQ_FD
++EVENTS = ZMQ_EVENTS
++TYPE = ZMQ_TYPE
++LINGER = ZMQ_LINGER
++RECONNECT_IVL = ZMQ_RECONNECT_IVL
++BACKLOG = ZMQ_BACKLOG
++
++# As new constants are added in future versions, add a new block here
++# like the two above, checking agains the relevant value for ZMQ_VERSION.
++# The constants will need to be added to libzmq.pxd and utils/zmq_compat.h
++# as well.
++
++#-----------------------------------------------------------------------------
++# Error handling
++#-----------------------------------------------------------------------------
++
++# Often used standard errnos
++from errno import (
++ EAGAIN,
++ EINVAL,
++ EFAULT,
++ ENOMEM,
++ ENODEV
++)
++
++# For Windows compatability
++ENOTSUP = ZMQ_ENOTSUP
++EPROTONOSUPPORT = ZMQ_EPROTONOSUPPORT
++ENOBUFS = ZMQ_ENOBUFS
++ENETDOWN = ZMQ_ENETDOWN
++EADDRINUSE = ZMQ_EADDRINUSE
++EADDRNOTAVAIL = ZMQ_EADDRNOTAVAIL
++ECONNREFUSED = ZMQ_ECONNREFUSED
++EINPROGRESS = ZMQ_EINPROGRESS
++ENOTSOCK = ZMQ_ENOTSOCK
++
++# new errnos in zmq3
++EMSGSIZE = ZMQ_EMSGSIZE
++EAFNOSUPPORT = ZMQ_EAFNOSUPPORT
++ENETUNREACH = ZMQ_ENETUNREACH
++ECONNABORTED = ZMQ_ECONNABORTED
++ECONNRESET = ZMQ_ECONNRESET
++ENOTCONN = ZMQ_ENOTCONN
++ETIMEDOUT = ZMQ_ETIMEDOUT
++EHOSTUNREACH = ZMQ_EHOSTUNREACH
++ENETRESET = ZMQ_ENETRESET
++
++# 0MQ Native
++EFSM = ZMQ_EFSM
++ENOCOMPATPROTO = ZMQ_ENOCOMPATPROTO
++ETERM = ZMQ_ETERM
++EMTHREAD = ZMQ_EMTHREAD
++
++#-----------------------------------------------------------------------------
++# Symbols to export
++#-----------------------------------------------------------------------------
++_names = list(locals().keys())
++__all__ = [ key for key in _names if not key.startswith('_') ]
+diff --git a/zmq/core/_zcontext.pxd b/zmq/core/_zcontext.pxd
+new file mode 100644
+index 0000000..e399de5
+--- /dev/null
++++ b/zmq/core/_zcontext.pxd
+@@ -0,0 +1,40 @@
++"""0MQ Context class declaration."""
++
++#
++# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
++#
++# This file is part of pyzmq.
++#
++# pyzmq is free software; you can redistribute it and/or modify it under
++# the terms of the Lesser GNU General Public License as published by
++# the Free Software Foundation; either version 3 of the License, or
++# (at your option) any later version.
++#
++# pyzmq is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++# Lesser GNU General Public License for more details.
++#
++# You should have received a copy of the Lesser GNU General Public License
++# along with this program. If not, see <http://www.gnu.org/licenses/>.
++#
++
++#-----------------------------------------------------------------------------
++# Code
++#-----------------------------------------------------------------------------
++
++cdef class Context:
++ """Manage the lifecycle of a 0MQ context."""
++
++ cdef object __weakref__ # enable weakref
++ cdef void *handle # The C handle for the underlying zmq object.
++ cdef void **_sockets # A C-array containg socket handles
++ cdef size_t _n_sockets # the number of sockets
++ cdef size_t _max_sockets # the size of the _sockets array
++ cdef int _pid # the pid of the process which created me (for fork safety)
++
++ cdef public object closed # bool property for a closed context.
++ # helpers for events on _sockets in Socket.__cinit__()/close()
++ cdef inline void _add_socket(self, void* handle)
++ cdef inline void _remove_socket(self, void* handle)
++
+diff --git a/zmq/core/_zcontext.pyx b/zmq/core/_zcontext.pyx
+new file mode 100644
+index 0000000..0917c66
+--- /dev/null
++++ b/zmq/core/_zcontext.pyx
+@@ -0,0 +1,254 @@
++"""0MQ Context class."""
++
++#
++# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
++#
++# This file is part of pyzmq.
++#
++# pyzmq is free software; you can redistribute it and/or modify it under
++# the terms of the Lesser GNU General Public License as published by
++# the Free Software Foundation; either version 3 of the License, or
++# (at your option) any later version.
++#
++# pyzmq is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++# Lesser GNU General Public License for more details.
++#
++# You should have received a copy of the Lesser GNU General Public License
++# along with this program. If not, see <http://www.gnu.org/licenses/>.
++#
++
++#-----------------------------------------------------------------------------
++# Imports
++#-----------------------------------------------------------------------------
++
++from libc.stdlib cimport free, malloc, realloc
++
++from libzmq cimport *
++
++cdef extern from "getpid_compat.h":
++ int getpid()
++
++from zmq.error import ZMQError
++from zmq.core.checkrc cimport _check_rc
++
++#-----------------------------------------------------------------------------
++# Code
++#-----------------------------------------------------------------------------
++
++_instance = None
++
++cdef class Context:
++ """Context(io_threads=1)
++
++ Manage the lifecycle of a 0MQ context.
++
++ Parameters
++ ----------
++ io_threads : int
++ The number of IO threads.
++ """
++
++ def __cinit__(self, int io_threads = 1, **kwargs):
++ self.handle = NULL
++ self._sockets = NULL
++
++ if ZMQ_VERSION_MAJOR >= 3:
++ self.handle = zmq_ctx_new()
++ else:
++ self.handle = zmq_init(io_threads)
++
++ if self.handle == NULL:
++ raise ZMQError()
++
++ cdef int rc = 0
++ if ZMQ_VERSION_MAJOR >= 3:
++ rc = zmq_ctx_set(self.handle, ZMQ_IO_THREADS, io_threads)
++ _check_rc(rc)
++
++ self.closed = False
++ self._n_sockets = 0
++ self._max_sockets = 32
++
++ self._sockets = <void **>malloc(self._max_sockets*sizeof(void *))
++ if self._sockets == NULL:
++ raise MemoryError("Could not allocate _sockets array")
++
++ self._pid = getpid()
++
++ def __init__(self, io_threads=1):
++ # no-op
++ pass
++
++
++ def __del__(self):
++ """deleting a Context should terminate it, without trying non-threadsafe destroy"""
++ self.term()
++
++ def __dealloc__(self):
++ """don't touch members in dealloc, just cleanup allocations"""
++ cdef int rc
++ if self._sockets != NULL:
++ free(self._sockets)
++ self._sockets = NULL
++ self._n_sockets = 0
++ self.term()
++
++ cdef inline void _add_socket(self, void* handle):
++ """Add a socket handle to be closed when Context terminates.
++
++ This is to be called in the Socket constructor.
++ """
++ # print self._n_sockets, self._max_sockets
++ if self._n_sockets >= self._max_sockets:
++ self._max_sockets *= 2
++ self._sockets = <void **>realloc(self._sockets, self._max_sockets*sizeof(void *))
++ if self._sockets == NULL:
++ raise MemoryError("Could not reallocate _sockets array")
++
++ self._sockets[self._n_sockets] = handle
++ self._n_sockets += 1
++ # print self._n_sockets, self._max_sockets
++
++ cdef inline void _remove_socket(self, void* handle):
++ """Remove a socket from the collected handles.
++
++ This should be called by Socket.close, to prevent trying to
++ close a socket a second time.
++ """
++ cdef bint found = False
++
++ for idx in range(self._n_sockets):
++ if self._sockets[idx] == handle:
++ found=True
++ break
++
++ if found:
++ self._n_sockets -= 1
++ if self._n_sockets:
++ # move last handle to closed socket's index
++ self._sockets[idx] = self._sockets[self._n_sockets]
++
++ @property
++ def _handle(self):
++ return <Py_ssize_t> self.handle
++
++ def term(self):
++ """ctx.term()
++
++ Close or terminate the context.
++
++ This can be called to close the context by hand. If this is not called,
++ the context will automatically be closed when it is garbage collected.
++ """
++ cdef int rc
++ cdef int i=-1
++
++ if self.handle != NULL and not self.closed and getpid() == self._pid:
++ with nogil:
++ rc = zmq_ctx_destroy(self.handle)
++ _check_rc(rc)
++ self.handle = NULL
++ self.closed = True
++
++ def set(self, int option, optval):
++ """ctx.set(option, optval)
++
++ Set context options.
++
++ See the 0MQ API documentation for zmq_ctx_set
++ for details on specific options.
++
++ New in libzmq-3.2
++
++ Parameters
++ ----------
++ option : int
++ The option to set. Available values will depend on your
++ version of libzmq. Examples include::
++
++ zmq.IO_THREADS, zmq.MAX_SOCKETS
++
++ optval : int
++ The value of the option to set.
++ """
++ cdef int optval_int_c
++ cdef int rc
++ cdef char* optval_c
++
++ if self.closed:
++ raise RuntimeError("Context has been destroyed")
++
++ if not isinstance(optval, int):
++ raise TypeError('expected int, got: %r' % optval)
++ optval_int_c = optval
++ rc = zmq_ctx_set(self.handle, option, optval_int_c)
++ _check_rc(rc)
++
++ def get(self, int option):
++ """ctx.get(option)
++
++ Get the value of a context option.
++
++ See the 0MQ API documentation for zmq_ctx_get
++ for details on specific options.
++
++ New in libzmq-3.2
++
++ Parameters
++ ----------
++ option : int
++ The option to get. Available values will depend on your
++ version of libzmq. Examples include::
++
++ zmq.IO_THREADS, zmq.MAX_SOCKETS
++
++ Returns
++ -------
++ optval : int
++ The value of the option as an integer.
++ """
++ cdef int optval_int_c
++ cdef size_t sz
++ cdef int rc
++
++ if self.closed:
++ raise RuntimeError("Context has been destroyed")
++
++ rc = zmq_ctx_get(self.handle, option)
++ _check_rc(rc)
++
++ return rc
++
++ def destroy(self, linger=None):
++ """ctx.destroy(linger=None)
++
++ Close all sockets associated with this context, and then terminate
++ the context. If linger is specified,
++ the LINGER sockopt of the sockets will be set prior to closing.
++
++ WARNING:
++
++ destroy involves calling zmq_close(), which is *NOT* threadsafe.
++ If there are active sockets in other threads, this must not be called.
++ """
++
++ cdef int linger_c
++ cdef bint setlinger=False
++
++ if linger is not None:
++ linger_c = linger
++ setlinger=True
++ if self.handle != NULL and not self.closed and self._n_sockets:
++ while self._n_sockets:
++ if setlinger:
++ zmq_setsockopt(self._sockets[0], ZMQ_LINGER, &linger_c, sizeof(int))
++ rc = zmq_close(self._sockets[0])
++ if rc < 0 and zmq_errno() != ZMQ_ENOTSOCK:
++ raise ZMQError()
++ self._n_sockets -= 1
++ self._sockets[0] = self._sockets[self._n_sockets]
++ self.term()
++
++__all__ = ['Context']
+diff --git a/zmq/core/_zerror.pyx b/zmq/core/_zerror.pyx
+new file mode 100644
+index 0000000..85e785f
+--- /dev/null
++++ b/zmq/core/_zerror.pyx
+@@ -0,0 +1,56 @@
++"""0MQ Error classes and functions."""
++
++#
++# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
++#
++# This file is part of pyzmq.
++#
++# pyzmq is free software; you can redistribute it and/or modify it under
++# the terms of the Lesser GNU General Public License as published by
++# the Free Software Foundation; either version 3 of the License, or
++# (at your option) any later version.
++#
++# pyzmq is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++# Lesser GNU General Public License for more details.
++#
++# You should have received a copy of the Lesser GNU General Public License
++# along with this program. If not, see <http://www.gnu.org/licenses/>.
++#
++
++#-----------------------------------------------------------------------------
++# Imports
++#-----------------------------------------------------------------------------
++
++# allow const char*
++cdef extern from *:
++ ctypedef char* const_char_ptr "const char*"
++
++from libzmq cimport zmq_strerror, zmq_errno as zmq_errno_c
++
++from zmq.utils.strtypes import bytes
++
++def strerror(int errno):
++ """strerror(errno)
++
++ Return the error string given the error number.
++ """
++ cdef const_char_ptr str_e
++ # char * will be a bytes object:
++ str_e = zmq_strerror(errno)
++ if str is bytes:
++ # Python 2: str is bytes, so we already have the right type
++ return str_e
++ else:
++ # Python 3: decode bytes to unicode str
++ return str_e.decode()
++
++def zmq_errno():
++ """zmq_errno()
++
++ Return the integer errno of the most recent zmq error.
++ """
++ return zmq_errno_c()
++
++__all__ = ['strerror', 'zmq_errno']
+diff --git a/zmq/core/_zmessage.pxd b/zmq/core/_zmessage.pxd
+new file mode 100644
+index 0000000..a86a8e0
+--- /dev/null
++++ b/zmq/core/_zmessage.pxd
+@@ -0,0 +1,66 @@
++"""0MQ Message related class declarations."""
++
++#
++# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
++#
++# This file is part of pyzmq.
++#
++# pyzmq is free software; you can redistribute it and/or modify it under
++# the terms of the Lesser GNU General Public License as published by
++# the Free Software Foundation; either version 3 of the License, or
++# (at your option) any later version.
++#
++# pyzmq is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++# Lesser GNU General Public License for more details.
++#
++# You should have received a copy of the Lesser GNU General Public License
++# along with this program. If not, see <http://www.gnu.org/licenses/>.
++#
++
++#-----------------------------------------------------------------------------
++# Imports
++#-----------------------------------------------------------------------------
++
++from cpython cimport PyBytes_FromStringAndSize
++
++from libzmq cimport zmq_msg_t, zmq_msg_data, zmq_msg_size
++
++#-----------------------------------------------------------------------------
++# Code
++#-----------------------------------------------------------------------------
++
++cdef class MessageTracker(object):
++ """A class for tracking if 0MQ is done using one or more messages."""
++
++ cdef set events # Message Event objects to track.
++ cdef set peers # Other Message or MessageTracker objects.
++
++
++cdef class Frame:
++ """A Message Frame class for non-copy send/recvs."""
++
++ cdef zmq_msg_t zmq_msg
++ cdef object _data # The actual message data as a Python object.
++ cdef object _buffer # A Python Buffer/View of the message contents
++ cdef object _bytes # A bytes/str copy of the message.
++ cdef bint _failed_init # Flag to handle failed zmq_msg_init
++ cdef public object tracker_event # Event for use with zmq_free_fn.
++ cdef public object tracker # MessageTracker object.
++ cdef public bint more # whether RCVMORE was set
++
++ cdef Frame fast_copy(self) # Create shallow copy of Message object.
++ cdef object _getbuffer(self) # Construct self._buffer.
++
++
++cdef inline object copy_zmq_msg_bytes(zmq_msg_t *zmq_msg):
++ """ Copy the data from a zmq_msg_t """
++ cdef char *data_c = NULL
++ cdef Py_ssize_t data_len_c
++ with nogil:
++ data_c = <char *>zmq_msg_data(zmq_msg)
++ data_len_c = zmq_msg_size(zmq_msg)
++ return PyBytes_FromStringAndSize(data_c, data_len_c)
++
++
+diff --git a/zmq/core/_zmessage.pyx b/zmq/core/_zmessage.pyx
+new file mode 100644
+index 0000000..1d358ab
+--- /dev/null
++++ b/zmq/core/_zmessage.pyx
+@@ -0,0 +1,297 @@
++"""0MQ Message related classes."""
++
++#
++# Copyright (c) 2013 Brian E. Granger & Min Ragan-Kelley
++#
++# This file is part of pyzmq.
++#
++# pyzmq is free software; you can redistribute it and/or modify it under
++# the terms of the Lesser GNU General Public License as published by
++# the Free Software Foundation; either version 3 of the License, or
++# (at your option) any later version.
++#
++# pyzmq is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++# Lesser GNU General Public License for more details.
++#
++# You should have received a copy of the Lesser GNU General Public License
++# along with this program. If not, see <http://www.gnu.org/licenses/>.
++#
++
++#-----------------------------------------------------------------------------
++# Imports
++#-----------------------------------------------------------------------------
++
++# get version-independent aliases:
++cdef extern from "pyversion_compat.h":
++ pass
++
++from cpython cimport Py_DECREF, Py_INCREF
++
++from buffers cimport asbuffer_r, viewfromobject_r
++
++cdef extern from "Python.h":
++ ctypedef int Py_ssize_t
++
++from libzmq cimport *
++
++import time
++
++try:
++ # below 3.3
++ from threading import _Event as Event
++except (ImportError, AttributeError):
++ # python throws ImportError, cython throws AttributeError
++ from threading import Event
++
++import zmq
++from zmq.core.checkrc cimport _check_rc
++from zmq.utils.strtypes import bytes,unicode,basestring
++
++#-----------------------------------------------------------------------------
++# Code
++#-----------------------------------------------------------------------------
++
++
++cdef void free_python_msg(void *data, void *hint) with gil:
++ """A function for DECREF'ing Python based messages."""
++ if hint != NULL:
++ tracker_event = (<tuple>hint)[1]
++ Py_DECREF(<object>hint)
++ if isinstance(tracker_event, Event):
++ # don't assert before DECREF:
++ # assert tracker_queue.empty(), "somebody else wrote to my Queue!"
++ tracker_event.set()
++ tracker_event = None
++
++
++cdef class Frame:
++ """Frame(data=None, track=False)
++
++ A zmq message Frame class for non-copy send/recvs.
++
++ This class is only needed if you want to do non-copying send and recvs.
++ When you pass a string to this class, like ``Frame(s)``, the
++ ref-count of `s` is increased by two: once because the Frame saves `s` as
++ an instance attribute and another because a ZMQ message is created that
++ points to the buffer of `s`. This second ref-count increase makes sure
++ that `s` lives until all messages that use it have been sent. Once 0MQ
++ sends all the messages and it doesn't need the buffer of s, 0MQ will call
++ ``Py_DECREF(s)``.
++
++ Parameters
++ ----------
++
++ data : object, optional
++ any object that provides the buffer interface will be used to
++ construct the 0MQ message data.
++ track : bool [default: False]
++ whether a MessageTracker_ should be created to track this object.
++ Tracking a message has a cost at creation, because it creates a threadsafe
++ Event object.
++
++ """
++
++ def __cinit__(self, object data=None, track=False, **kwargs):
++ cdef int rc
++ cdef char *data_c = NULL
++ cdef Py_ssize_t data_len_c=0
++ cdef object hint
++
++ # init more as False
++ self.more = False
++
++ # Save the data object in case the user wants the the data as a str.
++ self._data = data
++ self._failed_init = True # bool switch for dealloc
++ self._buffer = None # buffer view of data
++ self._bytes = None # bytes copy of data
++
++ # Event and MessageTracker for monitoring when zmq is done with data:
++ if track:
++ evt = Event()
++ self.tracker_event = evt
++ self.tracker = zmq.MessageTracker(evt)
++ else:
++ self.tracker_event = None
++ self.tracker = None
++
++ if isinstance(data, unicode):
++ raise TypeError("Unicode objects not allowed. Only: str/bytes, buffer interfaces.")
++
++ if data is None:
++ with nogil:
++ rc = zmq_msg_init(&self.zmq_msg)
++ _check_rc(rc)
++ self._failed_init = False
++ return
++ else:
++ asbuffer_r(data, <void **>&data_c, &data_len_c)
++ # We INCREF the *original* Python object (not self) and pass it
++ # as the hint below. This allows other copies of this Frame
++ # object to take over the ref counting of data properly.
++ hint = (data, self.tracker_event)
++ Py_INCREF(hint)
++ with nogil:
++ rc = zmq_msg_init_data(
++ &self.zmq_msg, <void *>data_c, data_len_c,
++ <zmq_free_fn *>free_python_msg, <void *>hint
++ )
++ if rc != 0:
++ Py_DECREF(hint)
++ _check_rc(rc)
++ self._failed_init = False
++
++ def __init__(self, object data=None, track=False):
++ """Enforce signature"""
++ pass
++
++ def __dealloc__(self):
++ cdef int rc
++ if self._failed_init:
++ return
++ # This simply decreases the 0MQ ref-count of zmq_msg.
++ with nogil:
++ rc = zmq_msg_close(&self.zmq_msg)
++ _check_rc(rc)
++
++ # buffer interface code adapted from petsc4py by Lisandro Dalcin, a BSD project
++
++ def __getbuffer__(self, Py_buffer* buffer, int flags):
++ # new-style (memoryview) buffer interface
++ with nogil:
++ buffer.buf = zmq_msg_data(&self.zmq_msg)
++ buffer.len = zmq_msg_size(&self.zmq_msg)
++
++ buffer.obj = self
++ buffer.readonly = 1
++ buffer.format = "B"
++ buffer.ndim = 0
++ buffer.shape = NULL
++ buffer.strides = NULL
++ buffer.suboffsets = NULL
++ buffer.itemsize = 1
++ buffer.internal = NULL
++
++ def __getsegcount__(self, Py_ssize_t *lenp):
++ # required for getreadbuffer
++ if lenp != NULL:
++ with nogil:
++ lenp[0] = zmq_msg_size(&self.zmq_msg)
++ return 1
++
++ def __getreadbuffer__(self, Py_ssize_t idx, void **p):
++ # old-style (buffer) interface
++ cdef char *data_c = NULL
++ cdef Py_ssize_t data_len_c
++ if idx != 0:
++ raise SystemError("accessing non-existent buffer segment")
++ # read-only, because we don't want to allow
++ # editing of the message in-place
++ with nogil:
++ data_c = <char *>zmq_msg_data(&self.zmq_msg)
++ data_len_c = zmq_msg_size(&self.zmq_msg)
++ if p != NULL:
++ p[0] = <void*>data_c
++ return data_len_c
++
++ # end buffer interface
++
++ def __copy__(self):
++ """Create a shallow copy of the message.
++
++ This does not copy the contents of the Frame, just the pointer.
++ This will increment the 0MQ ref count of the message, but not
++ the ref count of the Python object. That is only done once when
++ the Python is first turned into a 0MQ message.
++ """
++ return self.fast_copy()
++
++ cdef Frame fast_copy(self):
++ """Fast, cdef'd version of shallow copy of the Frame."""
++ cdef Frame new_msg
++ new_msg = Frame()
++ # This does not copy the contents, but just increases the ref-count
++ # of the zmq_msg by one.
++ with nogil:
++ zmq_msg_copy(&new_msg.zmq_msg, &self.zmq_msg)
++ # Copy the ref to data so the copy won't create a copy when str is
++ # called.
++ if self._data is not None:
++ new_msg._data = self._data
++ if self._buffer is not None:
++ new_msg._buffer = self._buffer
++ if self._bytes is not None:
++ new_msg._bytes = self._bytes
++
++ # Frame copies share the tracker and tracker_event
++ new_msg.tracker_event = self.tracker_event
++ new_msg.tracker = self.tracker
++
++ return new_msg
++
++ def __len__(self):
++ """Return the length of the message in bytes."""
++ cdef size_t sz
++ with nogil:
++ sz = zmq_msg_size(&self.zmq_msg)
++ return sz
++ # return <int>zmq_msg_size(&self.zmq_msg)
++
++ def __str__(self):
++ """Return the str form of the message."""
++ if isinstance(self._data, bytes):
++ b = self._data
++ else:
++ b = self.bytes
++ if str is unicode:
++ return b.decode()
++ else:
++ return b
++
++ cdef inline object _getbuffer(self):
++ """Create a Python buffer/view of the message data.
++
++ This will be called only once, the first time the `buffer` property
++ is accessed. Subsequent calls use a cached copy.
++ """
++ if self._data is None:
++ return viewfromobject_r(self)
++ else:
++ return viewfromobject_r(self._data)
++
++ @property
++ def buffer(self):
++ """Get a read-only buffer view of the message contents."""
++ if self._buffer is None:
++ self._buffer = self._getbuffer()
++ return self._buffer
++
++ @property
++ def bytes(self):
++ """Get the message content as a Python str/bytes object.
++
++ The first time this property is accessed, a copy of the message
++ contents is made. From then on that same copy of the message is
++ returned.
++ """
++ if self._bytes is None:
++ self._bytes = copy_zmq_msg_bytes(&self.zmq_msg)
++ return self._bytes
++
++ def set(self, int option, int value):
++ """Set a message property"""
++ cdef int rc = zmq_msg_set(&self.zmq_msg, option, value)
++ _check_rc(rc)
++
++ def get(self, int option):
++ """Get a message property"""
++ cdef int rc = zmq_msg_get(&self.zmq_msg, option)
++ _check_rc(rc)
++ return rc
++
++# legacy Message name
++Message = Frame
++
++__all__ = ['Frame', 'Message']
+diff --git a/zmq/core/_zsocket.pxd b/zmq/core/_zsocket.pxd
+new file mode 100644
+index 0000000..68f96c8
+--- /dev/null
++++ b/zmq/core/_zsocket.pxd
+@@ -0,0 +1,48 @@
++"""0MQ Socket class declaration."""
++
++#
++# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
++#
++# This file is part of pyzmq.
++#
++# pyzmq is free software; you can redistribute it and/or modify it under
++# the terms of the Lesser GNU General Public License as published by
++# the Free Software Foundation; either version 3 of the License, or
++# (at your option) any later version.
++#
++# pyzmq is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++# Lesser GNU General Public License for more details.
++#
++# You should have received a copy of the Lesser GNU General Public License
++# along with this program. If not, see <http://www.gnu.org/licenses/>.
++#
++
++#-----------------------------------------------------------------------------
++# Imports
++#-----------------------------------------------------------------------------
++
++from _zcontext cimport Context
++
++#-----------------------------------------------------------------------------
++# Code
++#-----------------------------------------------------------------------------
++
++
++cdef class Socket:
++ """A 0MQ socket."""
++
++ cdef object __weakref__ # enable weakref
++ cdef void *handle # The C handle for the underlying zmq object.
++ cdef public int socket_type # The 0MQ socket type - REQ,REP, etc.
++ # Hold on to a reference to the context to make sure it is not garbage
++ # collected until the socket it done with it.
++ cdef public Context context # The zmq Context object that owns this.
++ cdef public bint _closed # bool property for a closed socket.
++ cdef int _pid # the pid of the process which created me (for fork safety)
++
++ # cpdef methods for direct-cython access:
++ cpdef object send(self, object data, int flags=*, copy=*, track=*)
++ cpdef object recv(self, int flags=*, copy=*, track=*)
++
+diff --git a/zmq/core/_zsocket.pyx b/zmq/core/_zsocket.pyx
+new file mode 100644
+index 0000000..a5e507d
+--- /dev/null
++++ b/zmq/core/_zsocket.pyx
+@@ -0,0 +1,628 @@
++"""0MQ Socket class."""
++
++#
++# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
++#
++# This file is part of pyzmq.
++#
++# pyzmq is free software; you can redistribute it and/or modify it under
++# the terms of the Lesser GNU General Public License as published by
++# the Free Software Foundation; either version 3 of the License, or
++# (at your option) any later version.
++#
++# pyzmq is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++# Lesser GNU General Public License for more details.
++#
++# You should have received a copy of the Lesser GNU General Public License
++# along with this program. If not, see <http://www.gnu.org/licenses/>.
++#
++
++#-----------------------------------------------------------------------------
++# Cython Imports
++#-----------------------------------------------------------------------------
++
++# get version-independent aliases:
++cdef extern from "pyversion_compat.h":
++ pass
++
++from libc.errno cimport ENAMETOOLONG
++from libc.string cimport memcpy
++
++from cpython cimport PyBytes_FromStringAndSize
++from cpython cimport PyBytes_AsString, PyBytes_Size
++from cpython cimport Py_DECREF, Py_INCREF
++
++from buffers cimport asbuffer_r, viewfromobject_r
++
++from libzmq cimport *
++from _zmessage cimport Frame, copy_zmq_msg_bytes
++
++from _zcontext cimport Context
++
++cdef extern from "Python.h":
++ ctypedef int Py_ssize_t
++
++cdef extern from "ipcmaxlen.h":
++ int get_ipc_path_max_len()
++
++cdef extern from "getpid_compat.h":
++ int getpid()
++
++
++#-----------------------------------------------------------------------------
++# Python Imports
++#-----------------------------------------------------------------------------
++
++import copy as copy_mod
++import time
++import sys
++import random
++import struct
++import codecs
++
++from zmq.utils import jsonapi
++
++try:
++ import cPickle
++ pickle = cPickle
++except:
++ cPickle = None
++ import pickle
++
++import zmq
++from zmq.core import _zconstants as constants
++from zmq.core._zconstants import *
++from zmq.core.checkrc cimport _check_rc
++from zmq.error import ZMQError, ZMQBindError
++from zmq.utils.strtypes import bytes,unicode,basestring
++
++#-----------------------------------------------------------------------------
++# Code
++#-----------------------------------------------------------------------------
++
++IPC_PATH_MAX_LEN = get_ipc_path_max_len()
++
++# inline some small socket submethods:
++# true methods frequently cannot be inlined, acc. Cython docs
++
++cdef inline _check_closed(Socket s, bint raise_notsup):
++ cdef int rc
++ cdef int errno
++ cdef int stype
++ cdef size_t sz=sizeof(int)
++ if s._closed:
++ if raise_notsup:
++ raise ZMQError(ENOTSUP)
++ else:
++ return True
++ else:
++ rc = zmq_getsockopt(s.handle, ZMQ_TYPE, <void *>&stype, &sz)
++ if rc < 0 and zmq_errno() == ENOTSOCK:
++ s._closed = True
++ if raise_notsup:
++ raise ZMQError(ENOTSUP)
++ else:
++ return True
++ else:
++ _check_rc(rc)
++ return False
++
++cdef inline Frame _recv_frame(void *handle, int flags=0, track=False):
++ """Receive a message in a non-copying manner and return a Frame."""
++ cdef int rc
++ cdef Frame msg
++ msg = Frame(track=track)
++
++ with nogil:
++ rc = zmq_msg_recv(&msg.zmq_msg, handle, flags)
++
++ _check_rc(rc)
++ return msg
++
++cdef inline object _recv_copy(void *handle, int flags=0):
++ """Receive a message and return a copy"""
++ cdef zmq_msg_t zmq_msg
++ with nogil:
++ zmq_msg_init (&zmq_msg)
++ rc = zmq_msg_recv(&zmq_msg, handle, flags)
++ _check_rc(rc)
++ msg_bytes = copy_zmq_msg_bytes(&zmq_msg)
++ with nogil:
++ zmq_msg_close(&zmq_msg)
++ return msg_bytes
++
++cdef inline object _send_frame(void *handle, Frame msg, int flags=0):
++ """Send a Frame on this socket in a non-copy manner."""
++ cdef int rc
++ cdef Frame msg_copy
++
++ # Always copy so the original message isn't garbage collected.
++ # This doesn't do a real copy, just a reference.
++ msg_copy = msg.fast_copy()
++
++ with nogil:
++ rc = zmq_msg_send(&msg_copy.zmq_msg, handle, flags)
++
++ _check_rc(rc)
++ return msg.tracker
++
++
++cdef inline object _send_copy(void *handle, object msg, int flags=0):
++ """Send a message on this socket by copying its content."""
++ cdef int rc, rc2
++ cdef zmq_msg_t data
++ cdef char *msg_c
++ cdef Py_ssize_t msg_c_len=0
++
++ # copy to c array:
++ asbuffer_r(msg, <void **>&msg_c, &msg_c_len)
++
++ # Copy the msg before sending. This avoids any complications with
++ # the GIL, etc.
++ # If zmq_msg_init_* fails we must not call zmq_msg_close (Bus Error)
++ with nogil:
++ rc = zmq_msg_init_size(&data, msg_c_len)
++
++ _check_rc(rc)
++
++ with nogil:
++ memcpy(zmq_msg_data(&data), msg_c, zmq_msg_size(&data))
++ rc = zmq_msg_send(&data, handle, flags)
++ rc2 = zmq_msg_close(&data)
++ _check_rc(rc)
++ _check_rc(rc2)
++
++
++cdef class Socket:
++ """Socket(context, socket_type)
++
++ A 0MQ socket.
++
++ These objects will generally be constructed via the socket() method of a Context object.
++
++ Note: 0MQ Sockets are *not* threadsafe. **DO NOT** share them across threads.
++
++ Parameters
++ ----------
++ context : Context
++ The 0MQ Context this Socket belongs to.
++ socket_type : int
++ The socket type, which can be any of the 0MQ socket types:
++ REQ, REP, PUB, SUB, PAIR, DEALER, ROUTER, PULL, PUSH, XPUB, XSUB.
++
++ See Also
++ --------
++ .Context.socket : method for creating a socket bound to a Context.
++ """
++
++ def __cinit__(self, Context context, int socket_type, *args, **kwrags):
++ cdef Py_ssize_t c_handle
++ c_handle = context._handle
++
++ self.handle = NULL
++ self.context = context
++ self.socket_type = socket_type
++ with nogil:
++ self.handle = zmq_socket(<void *>c_handle, socket_type)
++ if self.handle == NULL:
++ raise ZMQError()
++ self._closed = False
++ self._pid = getpid()
++ context._add_socket(self.handle)
++
++ def __dealloc__(self):
++ """close *and* remove from context's list
++
++ But be careful that context might not exist if called during gc
++ """
++ if self.handle != NULL and getpid() == self._pid:
++ rc = zmq_close(self.handle)
++ if rc != 0 and zmq_errno() != ENOTSOCK:
++ # ignore ENOTSOCK (closed by Context)
++ _check_rc(rc)
++ # during gc, self.context might be NULL
++ if self.context:
++ self.context._remove_socket(self.handle)
++
++ def __init__(self, context, socket_type):
++ pass
++
++ @property
++ def closed(self):
++ return _check_closed(self, False)
++
++ def close(self, linger=None):
++ """s.close(linger=None)
++
++ Close the socket.
++
++ If linger is specified, LINGER sockopt will be set prior to closing.
++
++ This can be called to close the socket by hand. If this is not
++ called, the socket will automatically be closed when it is
++ garbage collected.
++ """
++ cdef int rc=0
++ cdef int linger_c
++ cdef bint setlinger=False
++
++ if linger is not None:
++ linger_c = linger
++ setlinger=True
++
++ if self.handle != NULL and not self._closed and getpid() == self._pid:
++ if setlinger:
++ zmq_setsockopt(self.handle, ZMQ_LINGER, &linger_c, sizeof(int))
++ rc = zmq_close(self.handle)
++ if rc != 0 and zmq_errno() != ENOTSOCK:
++ # ignore ENOTSOCK (closed by Context)
++ _check_rc(rc)
++ self._closed = True
++ # during gc, self.context might be NULL
++ if self.context:
++ self.context._remove_socket(self.handle)
++ self.handle = NULL
++
++ def set(self, int option, optval):
++ """s.set(option, optval)
++
++ Set socket options.
++
++ See the 0MQ API documentation for details on specific options.
++
++ Parameters
++ ----------
++ option : int
++ The option to set. Available values will depend on your
++ version of libzmq. Examples include::
++
++ zmq.SUBSCRIBE, UNSUBSCRIBE, IDENTITY, HWM, LINGER, FD
++
++ optval : int or bytes
++ The value of the option to set.
++ """
++ cdef int64_t optval_int64_c
++ cdef int optval_int_c
++ cdef int rc
++ cdef char* optval_c
++ cdef Py_ssize_t sz
++
++ _check_closed(self, True)
++ if isinstance(optval, unicode):
++ raise TypeError("unicode not allowed, use setsockopt_string")
++
++ if option in zmq.constants.bytes_sockopts:
++ if not isinstance(optval, bytes):
++ raise TypeError('expected bytes, got: %r' % optval)
++ optval_c = PyBytes_AsString(optval)
++ sz = PyBytes_Size(optval)
++ with nogil:
++ rc = zmq_setsockopt(
++ self.handle, option,
++ optval_c, sz
++ )
++ elif option in zmq.constants.int64_sockopts:
++ if not isinstance(optval, int):
++ raise TypeError('expected int, got: %r' % optval)
++ optval_int64_c = optval
++ with nogil:
++ rc = zmq_setsockopt(
++ self.handle, option,
++ &optval_int64_c, sizeof(int64_t)
++ )
++ else:
++ # default is to assume int, which is what most new sockopts will be
++ # this lets pyzmq work with newer libzmq which may add constants
++ # pyzmq has not yet added, rather than artificially raising. Invalid
++ # sockopts will still raise just the same, but it will be libzmq doing
++ # the raising.
++ if not isinstance(optval, int):
++ raise TypeError('expected int, got: %r' % optval)
++ optval_int_c = optval
++ with nogil:
++ rc = zmq_setsockopt(
++ self.handle, option,
++ &optval_int_c, sizeof(int)
++ )
++
++ _check_rc(rc)
++
++ def get(self, int option):
++ """s.get(option)
++
++ Get the value of a socket option.
++
++ See the 0MQ API documentation for details on specific options.
++
++ Parameters
++ ----------
++ option : int
++ The option to get. Available values will depend on your
++ version of libzmq. Examples include::
++
++ zmq.IDENTITY, HWM, LINGER, FD, EVENTS
++
++ Returns
++ -------
++ optval : int or bytes
++ The value of the option as a bytestring or int.
++ """
++ cdef int64_t optval_int64_c
++ cdef int optval_int_c
++ cdef fd_t optval_fd_c
++ cdef char identity_str_c [255]
++ cdef size_t sz
++ cdef int rc
++
++ _check_closed(self, True)
++
++ if option in zmq.constants.bytes_sockopts:
++ sz = 255
++ with nogil:
++ rc = zmq_getsockopt(self.handle, option, <void *>identity_str_c, &sz)
++ _check_rc(rc)
++ result = PyBytes_FromStringAndSize(<char *>identity_str_c, sz)
++ elif option in zmq.constants.int64_sockopts:
++ sz = sizeof(int64_t)
++ with nogil:
++ rc = zmq_getsockopt(self.handle, option, <void *>&optval_int64_c, &sz)
++ _check_rc(rc)
++ result = optval_int64_c
++ elif option == ZMQ_FD:
++ sz = sizeof(fd_t)
++ with nogil:
++ rc = zmq_getsockopt(self.handle, option, <void *>&optval_fd_c, &sz)
++ _check_rc(rc)
++ result = optval_fd_c
++ else:
++ # default is to assume int, which is what most new sockopts will be
++ # this lets pyzmq work with newer libzmq which may add constants
++ # pyzmq has not yet added, rather than artificially raising. Invalid
++ # sockopts will still raise just the same, but it will be libzmq doing
++ # the raising.
++ sz = sizeof(int)
++ with nogil:
++ rc = zmq_getsockopt(self.handle, option, <void *>&optval_int_c, &sz)
++ _check_rc(rc)
++ result = optval_int_c
++
++ return result
++
++ def bind(self, addr):
++ """s.bind(addr)
++
++ Bind the socket to an address.
++
++ This causes the socket to listen on a network port. Sockets on the
++ other side of this connection will use ``Socket.connect(addr)`` to
++ connect to this socket.
++
++ Parameters
++ ----------
++ addr : str
++ The address string. This has the form 'protocol://interface:port',
++ for example 'tcp://127.0.0.1:5555'. Protocols supported include
++ tcp, udp, pgm, epgm, inproc and ipc. If the address is unicode, it is
++ encoded to utf-8 first.
++ """
++ cdef int rc
++ cdef char* c_addr
++
++ _check_closed(self, True)
++ if isinstance(addr, unicode):
++ addr = addr.encode('utf-8')
++ if not isinstance(addr, bytes):
++ raise TypeError('expected str, got: %r' % addr)
++ c_addr = addr
++ rc = zmq_bind(self.handle, c_addr)
++ if rc != 0:
++ if IPC_PATH_MAX_LEN and zmq_errno() == ENAMETOOLONG:
++ # py3compat: addr is bytes, but msg wants str
++ if str is unicode:
++ addr = addr.decode('utf-8', 'replace')
++ path = addr.split('://', 1)[-1]
++ msg = ('ipc path "{0}" is longer than {1} '
++ 'characters (sizeof(sockaddr_un.sun_path)). '
++ 'zmq.IPC_PATH_MAX_LEN constant can be used '
++ 'to check addr length (if it is defined).'
++ .format(path, IPC_PATH_MAX_LEN))
++ raise ZMQError(msg=msg)
++ _check_rc(rc)
++
++ def connect(self, addr):
++ """s.connect(addr)
++
++ Connect to a remote 0MQ socket.
++
++ Parameters
++ ----------
++ addr : str
++ The address string. This has the form 'protocol://interface:port',
++ for example 'tcp://127.0.0.1:5555'. Protocols supported are
++ tcp, upd, pgm, inproc and ipc. If the address is unicode, it is
++ encoded to utf-8 first.
++ """
++ cdef int rc
++ cdef char* c_addr
++
++ _check_closed(self, True)
++ if isinstance(addr, unicode):
++ addr = addr.encode('utf-8')
++ if not isinstance(addr, bytes):
++ raise TypeError('expected str, got: %r' % addr)
++ c_addr = addr
++
++ rc = zmq_connect(self.handle, c_addr)
++ if rc != 0:
++ raise ZMQError()
++
++ def unbind(self, addr):
++ """s.unbind(addr)
++
++ Unbind from an address (undoes a call to bind).
++
++ This feature requires libzmq-3
++
++ Parameters
++ ----------
++ addr : str
++ The address string. This has the form 'protocol://interface:port',
++ for example 'tcp://127.0.0.1:5555'. Protocols supported are
++ tcp, upd, pgm, inproc and ipc. If the address is unicode, it is
++ encoded to utf-8 first.
++ """
++ cdef int rc
++ cdef char* c_addr
++
++ if ZMQ_VERSION_MAJOR < 3:
++ raise NotImplementedError("unbind requires libzmq >= 3.0, have %s" % zmq.zmq_version())
++
++
++ _check_closed(self, True)
++ if isinstance(addr, unicode):
++ addr = addr.encode('utf-8')
++ if not isinstance(addr, bytes):
++ raise TypeError('expected str, got: %r' % addr)
++ c_addr = addr
++
++ rc = zmq_unbind(self.handle, c_addr)
++ if rc != 0:
++ raise ZMQError()
++
++ def disconnect(self, addr):
++ """s.disconnect(addr)
++
++ Disconnect from a remote 0MQ socket (undoes a call to connect).
++
++ This feature requires libzmq-3
++
++ Parameters
++ ----------
++ addr : str
++ The address string. This has the form 'protocol://interface:port',
++ for example 'tcp://127.0.0.1:5555'. Protocols supported are
++ tcp, upd, pgm, inproc and ipc. If the address is unicode, it is
++ encoded to utf-8 first.
++ """
++ cdef int rc
++ cdef char* c_addr
++
++ if ZMQ_VERSION_MAJOR < 3:
++ raise NotImplementedError("disconnect requires libzmq >= 3.0, have %s" % zmq.zmq_version())
++
++ _check_closed(self, True)
++ if isinstance(addr, unicode):
++ addr = addr.encode('utf-8')
++ if not isinstance(addr, bytes):
++ raise TypeError('expected str, got: %r' % addr)
++ c_addr = addr
++
++ rc = zmq_disconnect(self.handle, c_addr)
++ if rc != 0:
++ raise ZMQError()
++
++ #-------------------------------------------------------------------------
++ # Sending and receiving messages
++ #-------------------------------------------------------------------------
++
++ cpdef object send(self, object data, int flags=0, copy=True, track=False):
++ """s.send(data, flags=0, copy=True, track=False)
++
++ Send a message on this socket.
++
++ This queues the message to be sent by the IO thread at a later time.
++
++ Parameters
++ ----------
++ data : object, str, Frame
++ The content of the message.
++ flags : int
++ Any supported flag: NOBLOCK, SNDMORE.
++ copy : bool
++ Should the message be sent in a copying or non-copying manner.
++ track : bool
++ Should the message be tracked for notification that ZMQ has
++ finished with it? (ignored if copy=True)
++
++ Returns
++ -------
++ None : if `copy` or not track
++ None if message was sent, raises an exception otherwise.
++ MessageTracker : if track and not copy
++ a MessageTracker object, whose `pending` property will
++ be True until the send is completed.
++
++ Raises
++ ------
++ TypeError
++ If a unicode object is passed
++ ValueError
++ If `track=True`, but an untracked Frame is passed.
++ ZMQError
++ If the send does not succeed for any reason.
++
++ """
++ _check_closed(self, True)
++
++ if isinstance(data, unicode):
++ raise TypeError("unicode not allowed, use send_unicode")
++
++ if copy:
++ # msg.bytes never returns the input data object
++ # it is always a copy, but always the same copy
++ if isinstance(data, Frame):
++ data = data.buffer
++ return _send_copy(self.handle, data, flags)
++ else:
++ if isinstance(data, Frame):
++ if track and not data.tracker:
++ raise ValueError('Not a tracked message')
++ msg = data
++ else:
++ msg = Frame(data, track=track)
++ return _send_frame(self.handle, msg, flags)
++
++ cpdef object recv(self, int flags=0, copy=True, track=False):
++ """s.recv(flags=0, copy=True, track=False)
++
++ Receive a message.
++
++ Parameters
++ ----------
++ flags : int
++ Any supported flag: NOBLOCK. If NOBLOCK is set, this method
++ will raise a ZMQError with EAGAIN if a message is not ready.
++ If NOBLOCK is not set, then this method will block until a
++ message arrives.
++ copy : bool
++ Should the message be received in a copying or non-copying manner?
++ If False a Frame object is returned, if True a string copy of
++ message is returned.
++ track : bool
++ Should the message be tracked for notification that ZMQ has
++ finished with it? (ignored if copy=True)
++
++ Returns
++ -------
++ msg : bytes, Frame
++ The received message frame. If `copy` is False, then it will be a Frame,
++ otherwise it will be bytes.
++
++ Raises
++ ------
++ ZMQError
++ for any of the reasons zmq_msg_recv might fail.
++ """
++ _check_closed(self, True)
++
++ if copy:
++ return _recv_copy(self.handle, flags)
++ else:
++ frame = _recv_frame(self.handle, flags, track)
++ frame.more = self.getsockopt(zmq.RCVMORE)
++ return frame
++
++
++__all__ = ['Socket', 'IPC_PATH_MAX_LEN']
+diff --git a/zmq/core/_zstopwatch.pxd b/zmq/core/_zstopwatch.pxd
+new file mode 100644
+index 0000000..5d56166
+--- /dev/null
++++ b/zmq/core/_zstopwatch.pxd
+@@ -0,0 +1,31 @@
++"""0MQ Stopwatch class declaration."""
++
++#
++# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
++#
++# This file is part of pyzmq.
++#
++# pyzmq is free software; you can redistribute it and/or modify it under
++# the terms of the Lesser GNU General Public License as published by
++# the Free Software Foundation; either version 3 of the License, or
++# (at your option) any later version.
++#
++# pyzmq is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++# Lesser GNU General Public License for more details.
++#
++# You should have received a copy of the Lesser GNU General Public License
++# along with this program. If not, see <http://www.gnu.org/licenses/>.
++#
++
++#-----------------------------------------------------------------------------
++# Code
++#-----------------------------------------------------------------------------
++
++
++cdef class Stopwatch:
++ """A simple stopwatch based on zmq_stopwatch_start/stop."""
++
++ cdef void *watch # The C handle for the underlying zmq object
++
+diff --git a/zmq/core/_zstopwatch.pyx b/zmq/core/_zstopwatch.pyx
+new file mode 100644
+index 0000000..6d2fd61
+--- /dev/null
++++ b/zmq/core/_zstopwatch.pyx
+@@ -0,0 +1,90 @@
++"""0MQ Stopwatch class."""
++
++#
++# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
++#
++# This file is part of pyzmq.
++#
++# pyzmq is free software; you can redistribute it and/or modify it under
++# the terms of the Lesser GNU General Public License as published by
++# the Free Software Foundation; either version 3 of the License, or
++# (at your option) any later version.
++#
++# pyzmq is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++# Lesser GNU General Public License for more details.
++#
++# You should have received a copy of the Lesser GNU General Public License
++# along with this program. If not, see <http://www.gnu.org/licenses/>.
++#
++
++#-----------------------------------------------------------------------------
++# Imports
++#-----------------------------------------------------------------------------
++
++from libzmq cimport zmq_stopwatch_start, zmq_stopwatch_stop, zmq_sleep
++
++from zmq.error import ZMQError
++
++#-----------------------------------------------------------------------------
++# Code
++#-----------------------------------------------------------------------------
++
++cdef class Stopwatch:
++ """Stopwatch()
++
++ A simple stopwatch based on zmq_stopwatch_start/stop.
++
++ This class should be used for benchmarking and timing 0MQ code.
++ """
++
++ def __cinit__(self):
++ self.watch = NULL
++
++ def __dealloc__(self):
++ try:
++ self.stop()
++ except ZMQError:
++ pass
++
++ def start(self):
++ """s.start()
++
++ Start the stopwatch.
++ """
++ if self.watch == NULL:
++ with nogil:
++ self.watch = zmq_stopwatch_start()
++ else:
++ raise ZMQError('Stopwatch is already runing.')
++
++ def stop(self):
++ """s.stop()
++
++ Stop the stopwatch.
++
++ Returns
++ -------
++ t : unsigned long int
++ the number of microseconds since ``start()`` was called.
++ """
++ cdef unsigned long time
++ if self.watch == NULL:
++ raise ZMQError('Must start the Stopwatch before calling stop.')
++ else:
++ with nogil:
++ time = zmq_stopwatch_stop(self.watch)
++ self.watch = NULL
++ return time
++
++ def sleep(self, int seconds):
++ """s.sleep(seconds)
++
++ Sleep for an integer number of seconds.
++ """
++ with nogil:
++ zmq_sleep(seconds)
++
++
++__all__ = ['Stopwatch']
+diff --git a/zmq/core/constants.pyx b/zmq/core/constants.pyx
+deleted file mode 100644
+index fa2695d..0000000
+--- a/zmq/core/constants.pyx
++++ /dev/null
+@@ -1,190 +0,0 @@
+-"""0MQ Constants."""
+-
+-#
+-# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
+-#
+-# This file is part of pyzmq.
+-#
+-# pyzmq is free software; you can redistribute it and/or modify it under
+-# the terms of the Lesser GNU General Public License as published by
+-# the Free Software Foundation; either version 3 of the License, or
+-# (at your option) any later version.
+-#
+-# pyzmq is distributed in the hope that it will be useful,
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-# Lesser GNU General Public License for more details.
+-#
+-# You should have received a copy of the Lesser GNU General Public License
+-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+-#
+-
+-#-----------------------------------------------------------------------------
+-# Imports
+-#-----------------------------------------------------------------------------
+-
+-from libzmq cimport *
+-
+-#-----------------------------------------------------------------------------
+-# Python module level constants
+-#-----------------------------------------------------------------------------
+-
+-_optionals = []
+-
+-if ZMQ_VERSION < 30000:
+- # backport DONTWAIT as alias to NOBLOCK
+- NOBLOCK = ZMQ_NOBLOCK
+- DONTWAIT = ZMQ_NOBLOCK
+-else:
+- # keep NOBLOCK as alias for new DONTWAIT
+- NOBLOCK = ZMQ_DONTWAIT
+- DONTWAIT = ZMQ_DONTWAIT
+-
+-VERSION = ZMQ_VERSION
+-
+-# socket types
+-PAIR = ZMQ_PAIR
+-PUB = ZMQ_PUB
+-SUB = ZMQ_SUB
+-REQ = ZMQ_REQ
+-REP = ZMQ_REP
+-DEALER = ZMQ_DEALER
+-ROUTER = ZMQ_ROUTER
+-PULL = ZMQ_PULL
+-PUSH = ZMQ_PUSH
+-XPUB = ZMQ_XPUB
+-XSUB = ZMQ_XSUB
+-
+-# keep deprecated aliases
+-XREQ = DEALER
+-XREP = ROUTER
+-UPSTREAM = PULL
+-DOWNSTREAM = PUSH
+-
+-
+-# socket options
+-AFFINITY = ZMQ_AFFINITY
+-IDENTITY = ZMQ_IDENTITY
+-SUBSCRIBE = ZMQ_SUBSCRIBE
+-UNSUBSCRIBE = ZMQ_UNSUBSCRIBE
+-RATE = ZMQ_RATE
+-RECOVERY_IVL = ZMQ_RECOVERY_IVL
+-RECONNECT_IVL_MAX = ZMQ_RECONNECT_IVL_MAX
+-SNDBUF = ZMQ_SNDBUF
+-RCVBUF = ZMQ_RCVBUF
+-RCVMORE = ZMQ_RCVMORE
+-SNDMORE = ZMQ_SNDMORE
+-POLLIN = ZMQ_POLLIN
+-POLLOUT = ZMQ_POLLOUT
+-POLLERR = ZMQ_POLLERR
+-
+-STREAMER = ZMQ_STREAMER
+-FORWARDER = ZMQ_FORWARDER
+-QUEUE = ZMQ_QUEUE
+-
+-# sockopts new in 2.2.0
+-SNDTIMEO = ZMQ_SNDTIMEO
+-RCVTIMEO = ZMQ_RCVTIMEO
+-
+-# sockopts removed in 3.0.0
+-HWM = ZMQ_HWM
+-SWAP = ZMQ_SWAP
+-MCAST_LOOP = ZMQ_MCAST_LOOP
+-RECOVERY_IVL_MSEC = ZMQ_RECOVERY_IVL_MSEC
+-
+-# new in 3.x
+-IO_THREADS = ZMQ_IO_THREADS
+-MAX_SOCKETS = ZMQ_MAX_SOCKETS
+-
+-MORE = ZMQ_MORE
+-
+-MAXMSGSIZE = ZMQ_MAXMSGSIZE
+-SNDHWM = ZMQ_SNDHWM
+-RCVHWM = ZMQ_RCVHWM
+-MULTICAST_HOPS = ZMQ_MULTICAST_HOPS
+-IPV4ONLY = ZMQ_IPV4ONLY
+-LAST_ENDPOINT = ZMQ_LAST_ENDPOINT
+-
+-ROUTER_MANDATORY = ZMQ_ROUTER_MANDATORY
+-# aliases
+-ROUTER_BEHAVIOR = ROUTER_MANDATORY
+-FAIL_UNROUTABLE = ROUTER_MANDATORY
+-
+-TCP_KEEPALIVE = ZMQ_TCP_KEEPALIVE
+-TCP_KEEPALIVE_CNT = ZMQ_TCP_KEEPALIVE_CNT
+-TCP_KEEPALIVE_IDLE = ZMQ_TCP_KEEPALIVE_IDLE
+-TCP_KEEPALIVE_INTVL = ZMQ_TCP_KEEPALIVE_INTVL
+-TCP_ACCEPT_FILTER = ZMQ_TCP_ACCEPT_FILTER
+-DELAY_ATTACH_ON_CONNECT = ZMQ_DELAY_ATTACH_ON_CONNECT
+-XPUB_VERBOSE = ZMQ_XPUB_VERBOSE
+-ROUTER_RAW = ZMQ_ROUTER_RAW
+-
+-EVENT_CONNECTED = ZMQ_EVENT_CONNECTED
+-EVENT_CONNECT_DELAYED = ZMQ_EVENT_CONNECT_DELAYED
+-EVENT_CONNECT_RETRIED = ZMQ_EVENT_CONNECT_RETRIED
+-EVENT_LISTENING = ZMQ_EVENT_LISTENING
+-EVENT_BIND_FAILED = ZMQ_EVENT_BIND_FAILED
+-EVENT_ACCEPTED = ZMQ_EVENT_ACCEPTED
+-EVENT_ACCEPT_FAILED = ZMQ_EVENT_ACCEPT_FAILED
+-EVENT_CLOSED = ZMQ_EVENT_CLOSED
+-EVENT_CLOSE_FAILED = ZMQ_EVENT_CLOSE_FAILED
+-EVENT_DISCONNECTED = ZMQ_EVENT_DISCONNECTED
+-
+-FD = ZMQ_FD
+-EVENTS = ZMQ_EVENTS
+-TYPE = ZMQ_TYPE
+-LINGER = ZMQ_LINGER
+-RECONNECT_IVL = ZMQ_RECONNECT_IVL
+-BACKLOG = ZMQ_BACKLOG
+-
+-# As new constants are added in future versions, add a new block here
+-# like the two above, checking agains the relevant value for ZMQ_VERSION.
+-# The constants will need to be added to libzmq.pxd and utils/zmq_compat.h
+-# as well.
+-
+-#-----------------------------------------------------------------------------
+-# Error handling
+-#-----------------------------------------------------------------------------
+-
+-# Often used standard errnos
+-from errno import (
+- EAGAIN,
+- EINVAL,
+- EFAULT,
+- ENOMEM,
+- ENODEV
+-)
+-
+-# For Windows compatability
+-ENOTSUP = ZMQ_ENOTSUP
+-EPROTONOSUPPORT = ZMQ_EPROTONOSUPPORT
+-ENOBUFS = ZMQ_ENOBUFS
+-ENETDOWN = ZMQ_ENETDOWN
+-EADDRINUSE = ZMQ_EADDRINUSE
+-EADDRNOTAVAIL = ZMQ_EADDRNOTAVAIL
+-ECONNREFUSED = ZMQ_ECONNREFUSED
+-EINPROGRESS = ZMQ_EINPROGRESS
+-ENOTSOCK = ZMQ_ENOTSOCK
+-
+-# new errnos in zmq3
+-EMSGSIZE = ZMQ_EMSGSIZE
+-EAFNOSUPPORT = ZMQ_EAFNOSUPPORT
+-ENETUNREACH = ZMQ_ENETUNREACH
+-ECONNABORTED = ZMQ_ECONNABORTED
+-ECONNRESET = ZMQ_ECONNRESET
+-ENOTCONN = ZMQ_ENOTCONN
+-ETIMEDOUT = ZMQ_ETIMEDOUT
+-EHOSTUNREACH = ZMQ_EHOSTUNREACH
+-ENETRESET = ZMQ_ENETRESET
+-
+-# 0MQ Native
+-EFSM = ZMQ_EFSM
+-ENOCOMPATPROTO = ZMQ_ENOCOMPATPROTO
+-ETERM = ZMQ_ETERM
+-EMTHREAD = ZMQ_EMTHREAD
+-
+-#-----------------------------------------------------------------------------
+-# Symbols to export
+-#-----------------------------------------------------------------------------
+-_names = list(locals().keys())
+-__all__ = [ key for key in _names if not key.startswith('_') ]
+diff --git a/zmq/core/context.pxd b/zmq/core/context.pxd
+deleted file mode 100644
+index e399de5..0000000
+--- a/zmq/core/context.pxd
++++ /dev/null
+@@ -1,40 +0,0 @@
+-"""0MQ Context class declaration."""
+-
+-#
+-# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
+-#
+-# This file is part of pyzmq.
+-#
+-# pyzmq is free software; you can redistribute it and/or modify it under
+-# the terms of the Lesser GNU General Public License as published by
+-# the Free Software Foundation; either version 3 of the License, or
+-# (at your option) any later version.
+-#
+-# pyzmq is distributed in the hope that it will be useful,
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-# Lesser GNU General Public License for more details.
+-#
+-# You should have received a copy of the Lesser GNU General Public License
+-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+-#
+-
+-#-----------------------------------------------------------------------------
+-# Code
+-#-----------------------------------------------------------------------------
+-
+-cdef class Context:
+- """Manage the lifecycle of a 0MQ context."""
+-
+- cdef object __weakref__ # enable weakref
+- cdef void *handle # The C handle for the underlying zmq object.
+- cdef void **_sockets # A C-array containg socket handles
+- cdef size_t _n_sockets # the number of sockets
+- cdef size_t _max_sockets # the size of the _sockets array
+- cdef int _pid # the pid of the process which created me (for fork safety)
+-
+- cdef public object closed # bool property for a closed context.
+- # helpers for events on _sockets in Socket.__cinit__()/close()
+- cdef inline void _add_socket(self, void* handle)
+- cdef inline void _remove_socket(self, void* handle)
+-
+diff --git a/zmq/core/context.pyx b/zmq/core/context.pyx
+deleted file mode 100644
+index 0917c66..0000000
+--- a/zmq/core/context.pyx
++++ /dev/null
+@@ -1,254 +0,0 @@
+-"""0MQ Context class."""
+-
+-#
+-# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
+-#
+-# This file is part of pyzmq.
+-#
+-# pyzmq is free software; you can redistribute it and/or modify it under
+-# the terms of the Lesser GNU General Public License as published by
+-# the Free Software Foundation; either version 3 of the License, or
+-# (at your option) any later version.
+-#
+-# pyzmq is distributed in the hope that it will be useful,
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-# Lesser GNU General Public License for more details.
+-#
+-# You should have received a copy of the Lesser GNU General Public License
+-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+-#
+-
+-#-----------------------------------------------------------------------------
+-# Imports
+-#-----------------------------------------------------------------------------
+-
+-from libc.stdlib cimport free, malloc, realloc
+-
+-from libzmq cimport *
+-
+-cdef extern from "getpid_compat.h":
+- int getpid()
+-
+-from zmq.error import ZMQError
+-from zmq.core.checkrc cimport _check_rc
+-
+-#-----------------------------------------------------------------------------
+-# Code
+-#-----------------------------------------------------------------------------
+-
+-_instance = None
+-
+-cdef class Context:
+- """Context(io_threads=1)
+-
+- Manage the lifecycle of a 0MQ context.
+-
+- Parameters
+- ----------
+- io_threads : int
+- The number of IO threads.
+- """
+-
+- def __cinit__(self, int io_threads = 1, **kwargs):
+- self.handle = NULL
+- self._sockets = NULL
+-
+- if ZMQ_VERSION_MAJOR >= 3:
+- self.handle = zmq_ctx_new()
+- else:
+- self.handle = zmq_init(io_threads)
+-
+- if self.handle == NULL:
+- raise ZMQError()
+-
+- cdef int rc = 0
+- if ZMQ_VERSION_MAJOR >= 3:
+- rc = zmq_ctx_set(self.handle, ZMQ_IO_THREADS, io_threads)
+- _check_rc(rc)
+-
+- self.closed = False
+- self._n_sockets = 0
+- self._max_sockets = 32
+-
+- self._sockets = <void **>malloc(self._max_sockets*sizeof(void *))
+- if self._sockets == NULL:
+- raise MemoryError("Could not allocate _sockets array")
+-
+- self._pid = getpid()
+-
+- def __init__(self, io_threads=1):
+- # no-op
+- pass
+-
+-
+- def __del__(self):
+- """deleting a Context should terminate it, without trying non-threadsafe destroy"""
+- self.term()
+-
+- def __dealloc__(self):
+- """don't touch members in dealloc, just cleanup allocations"""
+- cdef int rc
+- if self._sockets != NULL:
+- free(self._sockets)
+- self._sockets = NULL
+- self._n_sockets = 0
+- self.term()
+-
+- cdef inline void _add_socket(self, void* handle):
+- """Add a socket handle to be closed when Context terminates.
+-
+- This is to be called in the Socket constructor.
+- """
+- # print self._n_sockets, self._max_sockets
+- if self._n_sockets >= self._max_sockets:
+- self._max_sockets *= 2
+- self._sockets = <void **>realloc(self._sockets, self._max_sockets*sizeof(void *))
+- if self._sockets == NULL:
+- raise MemoryError("Could not reallocate _sockets array")
+-
+- self._sockets[self._n_sockets] = handle
+- self._n_sockets += 1
+- # print self._n_sockets, self._max_sockets
+-
+- cdef inline void _remove_socket(self, void* handle):
+- """Remove a socket from the collected handles.
+-
+- This should be called by Socket.close, to prevent trying to
+- close a socket a second time.
+- """
+- cdef bint found = False
+-
+- for idx in range(self._n_sockets):
+- if self._sockets[idx] == handle:
+- found=True
+- break
+-
+- if found:
+- self._n_sockets -= 1
+- if self._n_sockets:
+- # move last handle to closed socket's index
+- self._sockets[idx] = self._sockets[self._n_sockets]
+-
+- @property
+- def _handle(self):
+- return <Py_ssize_t> self.handle
+-
+- def term(self):
+- """ctx.term()
+-
+- Close or terminate the context.
+-
+- This can be called to close the context by hand. If this is not called,
+- the context will automatically be closed when it is garbage collected.
+- """
+- cdef int rc
+- cdef int i=-1
+-
+- if self.handle != NULL and not self.closed and getpid() == self._pid:
+- with nogil:
+- rc = zmq_ctx_destroy(self.handle)
+- _check_rc(rc)
+- self.handle = NULL
+- self.closed = True
+-
+- def set(self, int option, optval):
+- """ctx.set(option, optval)
+-
+- Set context options.
+-
+- See the 0MQ API documentation for zmq_ctx_set
+- for details on specific options.
+-
+- New in libzmq-3.2
+-
+- Parameters
+- ----------
+- option : int
+- The option to set. Available values will depend on your
+- version of libzmq. Examples include::
+-
+- zmq.IO_THREADS, zmq.MAX_SOCKETS
+-
+- optval : int
+- The value of the option to set.
+- """
+- cdef int optval_int_c
+- cdef int rc
+- cdef char* optval_c
+-
+- if self.closed:
+- raise RuntimeError("Context has been destroyed")
+-
+- if not isinstance(optval, int):
+- raise TypeError('expected int, got: %r' % optval)
+- optval_int_c = optval
+- rc = zmq_ctx_set(self.handle, option, optval_int_c)
+- _check_rc(rc)
+-
+- def get(self, int option):
+- """ctx.get(option)
+-
+- Get the value of a context option.
+-
+- See the 0MQ API documentation for zmq_ctx_get
+- for details on specific options.
+-
+- New in libzmq-3.2
+-
+- Parameters
+- ----------
+- option : int
+- The option to get. Available values will depend on your
+- version of libzmq. Examples include::
+-
+- zmq.IO_THREADS, zmq.MAX_SOCKETS
+-
+- Returns
+- -------
+- optval : int
+- The value of the option as an integer.
+- """
+- cdef int optval_int_c
+- cdef size_t sz
+- cdef int rc
+-
+- if self.closed:
+- raise RuntimeError("Context has been destroyed")
+-
+- rc = zmq_ctx_get(self.handle, option)
+- _check_rc(rc)
+-
+- return rc
+-
+- def destroy(self, linger=None):
+- """ctx.destroy(linger=None)
+-
+- Close all sockets associated with this context, and then terminate
+- the context. If linger is specified,
+- the LINGER sockopt of the sockets will be set prior to closing.
+-
+- WARNING:
+-
+- destroy involves calling zmq_close(), which is *NOT* threadsafe.
+- If there are active sockets in other threads, this must not be called.
+- """
+-
+- cdef int linger_c
+- cdef bint setlinger=False
+-
+- if linger is not None:
+- linger_c = linger
+- setlinger=True
+- if self.handle != NULL and not self.closed and self._n_sockets:
+- while self._n_sockets:
+- if setlinger:
+- zmq_setsockopt(self._sockets[0], ZMQ_LINGER, &linger_c, sizeof(int))
+- rc = zmq_close(self._sockets[0])
+- if rc < 0 and zmq_errno() != ZMQ_ENOTSOCK:
+- raise ZMQError()
+- self._n_sockets -= 1
+- self._sockets[0] = self._sockets[self._n_sockets]
+- self.term()
+-
+-__all__ = ['Context']
+diff --git a/zmq/core/error.pyx b/zmq/core/error.pyx
+deleted file mode 100644
+index 85e785f..0000000
+--- a/zmq/core/error.pyx
++++ /dev/null
+@@ -1,56 +0,0 @@
+-"""0MQ Error classes and functions."""
+-
+-#
+-# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
+-#
+-# This file is part of pyzmq.
+-#
+-# pyzmq is free software; you can redistribute it and/or modify it under
+-# the terms of the Lesser GNU General Public License as published by
+-# the Free Software Foundation; either version 3 of the License, or
+-# (at your option) any later version.
+-#
+-# pyzmq is distributed in the hope that it will be useful,
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-# Lesser GNU General Public License for more details.
+-#
+-# You should have received a copy of the Lesser GNU General Public License
+-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+-#
+-
+-#-----------------------------------------------------------------------------
+-# Imports
+-#-----------------------------------------------------------------------------
+-
+-# allow const char*
+-cdef extern from *:
+- ctypedef char* const_char_ptr "const char*"
+-
+-from libzmq cimport zmq_strerror, zmq_errno as zmq_errno_c
+-
+-from zmq.utils.strtypes import bytes
+-
+-def strerror(int errno):
+- """strerror(errno)
+-
+- Return the error string given the error number.
+- """
+- cdef const_char_ptr str_e
+- # char * will be a bytes object:
+- str_e = zmq_strerror(errno)
+- if str is bytes:
+- # Python 2: str is bytes, so we already have the right type
+- return str_e
+- else:
+- # Python 3: decode bytes to unicode str
+- return str_e.decode()
+-
+-def zmq_errno():
+- """zmq_errno()
+-
+- Return the integer errno of the most recent zmq error.
+- """
+- return zmq_errno_c()
+-
+-__all__ = ['strerror', 'zmq_errno']
+diff --git a/zmq/core/message.pxd b/zmq/core/message.pxd
+deleted file mode 100644
+index a86a8e0..0000000
+--- a/zmq/core/message.pxd
++++ /dev/null
+@@ -1,66 +0,0 @@
+-"""0MQ Message related class declarations."""
+-
+-#
+-# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
+-#
+-# This file is part of pyzmq.
+-#
+-# pyzmq is free software; you can redistribute it and/or modify it under
+-# the terms of the Lesser GNU General Public License as published by
+-# the Free Software Foundation; either version 3 of the License, or
+-# (at your option) any later version.
+-#
+-# pyzmq is distributed in the hope that it will be useful,
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-# Lesser GNU General Public License for more details.
+-#
+-# You should have received a copy of the Lesser GNU General Public License
+-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+-#
+-
+-#-----------------------------------------------------------------------------
+-# Imports
+-#-----------------------------------------------------------------------------
+-
+-from cpython cimport PyBytes_FromStringAndSize
+-
+-from libzmq cimport zmq_msg_t, zmq_msg_data, zmq_msg_size
+-
+-#-----------------------------------------------------------------------------
+-# Code
+-#-----------------------------------------------------------------------------
+-
+-cdef class MessageTracker(object):
+- """A class for tracking if 0MQ is done using one or more messages."""
+-
+- cdef set events # Message Event objects to track.
+- cdef set peers # Other Message or MessageTracker objects.
+-
+-
+-cdef class Frame:
+- """A Message Frame class for non-copy send/recvs."""
+-
+- cdef zmq_msg_t zmq_msg
+- cdef object _data # The actual message data as a Python object.
+- cdef object _buffer # A Python Buffer/View of the message contents
+- cdef object _bytes # A bytes/str copy of the message.
+- cdef bint _failed_init # Flag to handle failed zmq_msg_init
+- cdef public object tracker_event # Event for use with zmq_free_fn.
+- cdef public object tracker # MessageTracker object.
+- cdef public bint more # whether RCVMORE was set
+-
+- cdef Frame fast_copy(self) # Create shallow copy of Message object.
+- cdef object _getbuffer(self) # Construct self._buffer.
+-
+-
+-cdef inline object copy_zmq_msg_bytes(zmq_msg_t *zmq_msg):
+- """ Copy the data from a zmq_msg_t """
+- cdef char *data_c = NULL
+- cdef Py_ssize_t data_len_c
+- with nogil:
+- data_c = <char *>zmq_msg_data(zmq_msg)
+- data_len_c = zmq_msg_size(zmq_msg)
+- return PyBytes_FromStringAndSize(data_c, data_len_c)
+-
+-
+diff --git a/zmq/core/message.pyx b/zmq/core/message.pyx
+deleted file mode 100644
+index 1d358ab..0000000
+--- a/zmq/core/message.pyx
++++ /dev/null
+@@ -1,297 +0,0 @@
+-"""0MQ Message related classes."""
+-
+-#
+-# Copyright (c) 2013 Brian E. Granger & Min Ragan-Kelley
+-#
+-# This file is part of pyzmq.
+-#
+-# pyzmq is free software; you can redistribute it and/or modify it under
+-# the terms of the Lesser GNU General Public License as published by
+-# the Free Software Foundation; either version 3 of the License, or
+-# (at your option) any later version.
+-#
+-# pyzmq is distributed in the hope that it will be useful,
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-# Lesser GNU General Public License for more details.
+-#
+-# You should have received a copy of the Lesser GNU General Public License
+-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+-#
+-
+-#-----------------------------------------------------------------------------
+-# Imports
+-#-----------------------------------------------------------------------------
+-
+-# get version-independent aliases:
+-cdef extern from "pyversion_compat.h":
+- pass
+-
+-from cpython cimport Py_DECREF, Py_INCREF
+-
+-from buffers cimport asbuffer_r, viewfromobject_r
+-
+-cdef extern from "Python.h":
+- ctypedef int Py_ssize_t
+-
+-from libzmq cimport *
+-
+-import time
+-
+-try:
+- # below 3.3
+- from threading import _Event as Event
+-except (ImportError, AttributeError):
+- # python throws ImportError, cython throws AttributeError
+- from threading import Event
+-
+-import zmq
+-from zmq.core.checkrc cimport _check_rc
+-from zmq.utils.strtypes import bytes,unicode,basestring
+-
+-#-----------------------------------------------------------------------------
+-# Code
+-#-----------------------------------------------------------------------------
+-
+-
+-cdef void free_python_msg(void *data, void *hint) with gil:
+- """A function for DECREF'ing Python based messages."""
+- if hint != NULL:
+- tracker_event = (<tuple>hint)[1]
+- Py_DECREF(<object>hint)
+- if isinstance(tracker_event, Event):
+- # don't assert before DECREF:
+- # assert tracker_queue.empty(), "somebody else wrote to my Queue!"
+- tracker_event.set()
+- tracker_event = None
+-
+-
+-cdef class Frame:
+- """Frame(data=None, track=False)
+-
+- A zmq message Frame class for non-copy send/recvs.
+-
+- This class is only needed if you want to do non-copying send and recvs.
+- When you pass a string to this class, like ``Frame(s)``, the
+- ref-count of `s` is increased by two: once because the Frame saves `s` as
+- an instance attribute and another because a ZMQ message is created that
+- points to the buffer of `s`. This second ref-count increase makes sure
+- that `s` lives until all messages that use it have been sent. Once 0MQ
+- sends all the messages and it doesn't need the buffer of s, 0MQ will call
+- ``Py_DECREF(s)``.
+-
+- Parameters
+- ----------
+-
+- data : object, optional
+- any object that provides the buffer interface will be used to
+- construct the 0MQ message data.
+- track : bool [default: False]
+- whether a MessageTracker_ should be created to track this object.
+- Tracking a message has a cost at creation, because it creates a threadsafe
+- Event object.
+-
+- """
+-
+- def __cinit__(self, object data=None, track=False, **kwargs):
+- cdef int rc
+- cdef char *data_c = NULL
+- cdef Py_ssize_t data_len_c=0
+- cdef object hint
+-
+- # init more as False
+- self.more = False
+-
+- # Save the data object in case the user wants the the data as a str.
+- self._data = data
+- self._failed_init = True # bool switch for dealloc
+- self._buffer = None # buffer view of data
+- self._bytes = None # bytes copy of data
+-
+- # Event and MessageTracker for monitoring when zmq is done with data:
+- if track:
+- evt = Event()
+- self.tracker_event = evt
+- self.tracker = zmq.MessageTracker(evt)
+- else:
+- self.tracker_event = None
+- self.tracker = None
+-
+- if isinstance(data, unicode):
+- raise TypeError("Unicode objects not allowed. Only: str/bytes, buffer interfaces.")
+-
+- if data is None:
+- with nogil:
+- rc = zmq_msg_init(&self.zmq_msg)
+- _check_rc(rc)
+- self._failed_init = False
+- return
+- else:
+- asbuffer_r(data, <void **>&data_c, &data_len_c)
+- # We INCREF the *original* Python object (not self) and pass it
+- # as the hint below. This allows other copies of this Frame
+- # object to take over the ref counting of data properly.
+- hint = (data, self.tracker_event)
+- Py_INCREF(hint)
+- with nogil:
+- rc = zmq_msg_init_data(
+- &self.zmq_msg, <void *>data_c, data_len_c,
+- <zmq_free_fn *>free_python_msg, <void *>hint
+- )
+- if rc != 0:
+- Py_DECREF(hint)
+- _check_rc(rc)
+- self._failed_init = False
+-
+- def __init__(self, object data=None, track=False):
+- """Enforce signature"""
+- pass
+-
+- def __dealloc__(self):
+- cdef int rc
+- if self._failed_init:
+- return
+- # This simply decreases the 0MQ ref-count of zmq_msg.
+- with nogil:
+- rc = zmq_msg_close(&self.zmq_msg)
+- _check_rc(rc)
+-
+- # buffer interface code adapted from petsc4py by Lisandro Dalcin, a BSD project
+-
+- def __getbuffer__(self, Py_buffer* buffer, int flags):
+- # new-style (memoryview) buffer interface
+- with nogil:
+- buffer.buf = zmq_msg_data(&self.zmq_msg)
+- buffer.len = zmq_msg_size(&self.zmq_msg)
+-
+- buffer.obj = self
+- buffer.readonly = 1
+- buffer.format = "B"
+- buffer.ndim = 0
+- buffer.shape = NULL
+- buffer.strides = NULL
+- buffer.suboffsets = NULL
+- buffer.itemsize = 1
+- buffer.internal = NULL
+-
+- def __getsegcount__(self, Py_ssize_t *lenp):
+- # required for getreadbuffer
+- if lenp != NULL:
+- with nogil:
+- lenp[0] = zmq_msg_size(&self.zmq_msg)
+- return 1
+-
+- def __getreadbuffer__(self, Py_ssize_t idx, void **p):
+- # old-style (buffer) interface
+- cdef char *data_c = NULL
+- cdef Py_ssize_t data_len_c
+- if idx != 0:
+- raise SystemError("accessing non-existent buffer segment")
+- # read-only, because we don't want to allow
+- # editing of the message in-place
+- with nogil:
+- data_c = <char *>zmq_msg_data(&self.zmq_msg)
+- data_len_c = zmq_msg_size(&self.zmq_msg)
+- if p != NULL:
+- p[0] = <void*>data_c
+- return data_len_c
+-
+- # end buffer interface
+-
+- def __copy__(self):
+- """Create a shallow copy of the message.
+-
+- This does not copy the contents of the Frame, just the pointer.
+- This will increment the 0MQ ref count of the message, but not
+- the ref count of the Python object. That is only done once when
+- the Python is first turned into a 0MQ message.
+- """
+- return self.fast_copy()
+-
+- cdef Frame fast_copy(self):
+- """Fast, cdef'd version of shallow copy of the Frame."""
+- cdef Frame new_msg
+- new_msg = Frame()
+- # This does not copy the contents, but just increases the ref-count
+- # of the zmq_msg by one.
+- with nogil:
+- zmq_msg_copy(&new_msg.zmq_msg, &self.zmq_msg)
+- # Copy the ref to data so the copy won't create a copy when str is
+- # called.
+- if self._data is not None:
+- new_msg._data = self._data
+- if self._buffer is not None:
+- new_msg._buffer = self._buffer
+- if self._bytes is not None:
+- new_msg._bytes = self._bytes
+-
+- # Frame copies share the tracker and tracker_event
+- new_msg.tracker_event = self.tracker_event
+- new_msg.tracker = self.tracker
+-
+- return new_msg
+-
+- def __len__(self):
+- """Return the length of the message in bytes."""
+- cdef size_t sz
+- with nogil:
+- sz = zmq_msg_size(&self.zmq_msg)
+- return sz
+- # return <int>zmq_msg_size(&self.zmq_msg)
+-
+- def __str__(self):
+- """Return the str form of the message."""
+- if isinstance(self._data, bytes):
+- b = self._data
+- else:
+- b = self.bytes
+- if str is unicode:
+- return b.decode()
+- else:
+- return b
+-
+- cdef inline object _getbuffer(self):
+- """Create a Python buffer/view of the message data.
+-
+- This will be called only once, the first time the `buffer` property
+- is accessed. Subsequent calls use a cached copy.
+- """
+- if self._data is None:
+- return viewfromobject_r(self)
+- else:
+- return viewfromobject_r(self._data)
+-
+- @property
+- def buffer(self):
+- """Get a read-only buffer view of the message contents."""
+- if self._buffer is None:
+- self._buffer = self._getbuffer()
+- return self._buffer
+-
+- @property
+- def bytes(self):
+- """Get the message content as a Python str/bytes object.
+-
+- The first time this property is accessed, a copy of the message
+- contents is made. From then on that same copy of the message is
+- returned.
+- """
+- if self._bytes is None:
+- self._bytes = copy_zmq_msg_bytes(&self.zmq_msg)
+- return self._bytes
+-
+- def set(self, int option, int value):
+- """Set a message property"""
+- cdef int rc = zmq_msg_set(&self.zmq_msg, option, value)
+- _check_rc(rc)
+-
+- def get(self, int option):
+- """Get a message property"""
+- cdef int rc = zmq_msg_get(&self.zmq_msg, option)
+- _check_rc(rc)
+- return rc
+-
+-# legacy Message name
+-Message = Frame
+-
+-__all__ = ['Frame', 'Message']
+diff --git a/zmq/core/socket.pxd b/zmq/core/socket.pxd
+deleted file mode 100644
+index 92253eb..0000000
+--- a/zmq/core/socket.pxd
++++ /dev/null
+@@ -1,48 +0,0 @@
+-"""0MQ Socket class declaration."""
+-
+-#
+-# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
+-#
+-# This file is part of pyzmq.
+-#
+-# pyzmq is free software; you can redistribute it and/or modify it under
+-# the terms of the Lesser GNU General Public License as published by
+-# the Free Software Foundation; either version 3 of the License, or
+-# (at your option) any later version.
+-#
+-# pyzmq is distributed in the hope that it will be useful,
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-# Lesser GNU General Public License for more details.
+-#
+-# You should have received a copy of the Lesser GNU General Public License
+-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+-#
+-
+-#-----------------------------------------------------------------------------
+-# Imports
+-#-----------------------------------------------------------------------------
+-
+-from context cimport Context
+-
+-#-----------------------------------------------------------------------------
+-# Code
+-#-----------------------------------------------------------------------------
+-
+-
+-cdef class Socket:
+- """A 0MQ socket."""
+-
+- cdef object __weakref__ # enable weakref
+- cdef void *handle # The C handle for the underlying zmq object.
+- cdef public int socket_type # The 0MQ socket type - REQ,REP, etc.
+- # Hold on to a reference to the context to make sure it is not garbage
+- # collected until the socket it done with it.
+- cdef public Context context # The zmq Context object that owns this.
+- cdef public bint _closed # bool property for a closed socket.
+- cdef int _pid # the pid of the process which created me (for fork safety)
+-
+- # cpdef methods for direct-cython access:
+- cpdef object send(self, object data, int flags=*, copy=*, track=*)
+- cpdef object recv(self, int flags=*, copy=*, track=*)
+-
+diff --git a/zmq/core/socket.pyx b/zmq/core/socket.pyx
+deleted file mode 100644
+index 16fbf7f..0000000
+--- a/zmq/core/socket.pyx
++++ /dev/null
+@@ -1,628 +0,0 @@
+-"""0MQ Socket class."""
+-
+-#
+-# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
+-#
+-# This file is part of pyzmq.
+-#
+-# pyzmq is free software; you can redistribute it and/or modify it under
+-# the terms of the Lesser GNU General Public License as published by
+-# the Free Software Foundation; either version 3 of the License, or
+-# (at your option) any later version.
+-#
+-# pyzmq is distributed in the hope that it will be useful,
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-# Lesser GNU General Public License for more details.
+-#
+-# You should have received a copy of the Lesser GNU General Public License
+-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+-#
+-
+-#-----------------------------------------------------------------------------
+-# Cython Imports
+-#-----------------------------------------------------------------------------
+-
+-# get version-independent aliases:
+-cdef extern from "pyversion_compat.h":
+- pass
+-
+-from libc.errno cimport ENAMETOOLONG
+-from libc.string cimport memcpy
+-
+-from cpython cimport PyBytes_FromStringAndSize
+-from cpython cimport PyBytes_AsString, PyBytes_Size
+-from cpython cimport Py_DECREF, Py_INCREF
+-
+-from buffers cimport asbuffer_r, viewfromobject_r
+-
+-from libzmq cimport *
+-from message cimport Frame, copy_zmq_msg_bytes
+-
+-from context cimport Context
+-
+-cdef extern from "Python.h":
+- ctypedef int Py_ssize_t
+-
+-cdef extern from "ipcmaxlen.h":
+- int get_ipc_path_max_len()
+-
+-cdef extern from "getpid_compat.h":
+- int getpid()
+-
+-
+-#-----------------------------------------------------------------------------
+-# Python Imports
+-#-----------------------------------------------------------------------------
+-
+-import copy as copy_mod
+-import time
+-import sys
+-import random
+-import struct
+-import codecs
+-
+-from zmq.utils import jsonapi
+-
+-try:
+- import cPickle
+- pickle = cPickle
+-except:
+- cPickle = None
+- import pickle
+-
+-import zmq
+-from zmq.core import constants
+-from zmq.core.constants import *
+-from zmq.core.checkrc cimport _check_rc
+-from zmq.error import ZMQError, ZMQBindError
+-from zmq.utils.strtypes import bytes,unicode,basestring
+-
+-#-----------------------------------------------------------------------------
+-# Code
+-#-----------------------------------------------------------------------------
+-
+-IPC_PATH_MAX_LEN = get_ipc_path_max_len()
+-
+-# inline some small socket submethods:
+-# true methods frequently cannot be inlined, acc. Cython docs
+-
+-cdef inline _check_closed(Socket s, bint raise_notsup):
+- cdef int rc
+- cdef int errno
+- cdef int stype
+- cdef size_t sz=sizeof(int)
+- if s._closed:
+- if raise_notsup:
+- raise ZMQError(ENOTSUP)
+- else:
+- return True
+- else:
+- rc = zmq_getsockopt(s.handle, ZMQ_TYPE, <void *>&stype, &sz)
+- if rc < 0 and zmq_errno() == ENOTSOCK:
+- s._closed = True
+- if raise_notsup:
+- raise ZMQError(ENOTSUP)
+- else:
+- return True
+- else:
+- _check_rc(rc)
+- return False
+-
+-cdef inline Frame _recv_frame(void *handle, int flags=0, track=False):
+- """Receive a message in a non-copying manner and return a Frame."""
+- cdef int rc
+- cdef Frame msg
+- msg = Frame(track=track)
+-
+- with nogil:
+- rc = zmq_msg_recv(&msg.zmq_msg, handle, flags)
+-
+- _check_rc(rc)
+- return msg
+-
+-cdef inline object _recv_copy(void *handle, int flags=0):
+- """Receive a message and return a copy"""
+- cdef zmq_msg_t zmq_msg
+- with nogil:
+- zmq_msg_init (&zmq_msg)
+- rc = zmq_msg_recv(&zmq_msg, handle, flags)
+- _check_rc(rc)
+- msg_bytes = copy_zmq_msg_bytes(&zmq_msg)
+- with nogil:
+- zmq_msg_close(&zmq_msg)
+- return msg_bytes
+-
+-cdef inline object _send_frame(void *handle, Frame msg, int flags=0):
+- """Send a Frame on this socket in a non-copy manner."""
+- cdef int rc
+- cdef Frame msg_copy
+-
+- # Always copy so the original message isn't garbage collected.
+- # This doesn't do a real copy, just a reference.
+- msg_copy = msg.fast_copy()
+-
+- with nogil:
+- rc = zmq_msg_send(&msg_copy.zmq_msg, handle, flags)
+-
+- _check_rc(rc)
+- return msg.tracker
+-
+-
+-cdef inline object _send_copy(void *handle, object msg, int flags=0):
+- """Send a message on this socket by copying its content."""
+- cdef int rc, rc2
+- cdef zmq_msg_t data
+- cdef char *msg_c
+- cdef Py_ssize_t msg_c_len=0
+-
+- # copy to c array:
+- asbuffer_r(msg, <void **>&msg_c, &msg_c_len)
+-
+- # Copy the msg before sending. This avoids any complications with
+- # the GIL, etc.
+- # If zmq_msg_init_* fails we must not call zmq_msg_close (Bus Error)
+- with nogil:
+- rc = zmq_msg_init_size(&data, msg_c_len)
+-
+- _check_rc(rc)
+-
+- with nogil:
+- memcpy(zmq_msg_data(&data), msg_c, zmq_msg_size(&data))
+- rc = zmq_msg_send(&data, handle, flags)
+- rc2 = zmq_msg_close(&data)
+- _check_rc(rc)
+- _check_rc(rc2)
+-
+-
+-cdef class Socket:
+- """Socket(context, socket_type)
+-
+- A 0MQ socket.
+-
+- These objects will generally be constructed via the socket() method of a Context object.
+-
+- Note: 0MQ Sockets are *not* threadsafe. **DO NOT** share them across threads.
+-
+- Parameters
+- ----------
+- context : Context
+- The 0MQ Context this Socket belongs to.
+- socket_type : int
+- The socket type, which can be any of the 0MQ socket types:
+- REQ, REP, PUB, SUB, PAIR, DEALER, ROUTER, PULL, PUSH, XPUB, XSUB.
+-
+- See Also
+- --------
+- .Context.socket : method for creating a socket bound to a Context.
+- """
+-
+- def __cinit__(self, Context context, int socket_type, *args, **kwrags):
+- cdef Py_ssize_t c_handle
+- c_handle = context._handle
+-
+- self.handle = NULL
+- self.context = context
+- self.socket_type = socket_type
+- with nogil:
+- self.handle = zmq_socket(<void *>c_handle, socket_type)
+- if self.handle == NULL:
+- raise ZMQError()
+- self._closed = False
+- self._pid = getpid()
+- context._add_socket(self.handle)
+-
+- def __dealloc__(self):
+- """close *and* remove from context's list
+-
+- But be careful that context might not exist if called during gc
+- """
+- if self.handle != NULL and getpid() == self._pid:
+- rc = zmq_close(self.handle)
+- if rc != 0 and zmq_errno() != ENOTSOCK:
+- # ignore ENOTSOCK (closed by Context)
+- _check_rc(rc)
+- # during gc, self.context might be NULL
+- if self.context:
+- self.context._remove_socket(self.handle)
+-
+- def __init__(self, context, socket_type):
+- pass
+-
+- @property
+- def closed(self):
+- return _check_closed(self, False)
+-
+- def close(self, linger=None):
+- """s.close(linger=None)
+-
+- Close the socket.
+-
+- If linger is specified, LINGER sockopt will be set prior to closing.
+-
+- This can be called to close the socket by hand. If this is not
+- called, the socket will automatically be closed when it is
+- garbage collected.
+- """
+- cdef int rc=0
+- cdef int linger_c
+- cdef bint setlinger=False
+-
+- if linger is not None:
+- linger_c = linger
+- setlinger=True
+-
+- if self.handle != NULL and not self._closed and getpid() == self._pid:
+- if setlinger:
+- zmq_setsockopt(self.handle, ZMQ_LINGER, &linger_c, sizeof(int))
+- rc = zmq_close(self.handle)
+- if rc != 0 and zmq_errno() != ENOTSOCK:
+- # ignore ENOTSOCK (closed by Context)
+- _check_rc(rc)
+- self._closed = True
+- # during gc, self.context might be NULL
+- if self.context:
+- self.context._remove_socket(self.handle)
+- self.handle = NULL
+-
+- def set(self, int option, optval):
+- """s.set(option, optval)
+-
+- Set socket options.
+-
+- See the 0MQ API documentation for details on specific options.
+-
+- Parameters
+- ----------
+- option : int
+- The option to set. Available values will depend on your
+- version of libzmq. Examples include::
+-
+- zmq.SUBSCRIBE, UNSUBSCRIBE, IDENTITY, HWM, LINGER, FD
+-
+- optval : int or bytes
+- The value of the option to set.
+- """
+- cdef int64_t optval_int64_c
+- cdef int optval_int_c
+- cdef int rc
+- cdef char* optval_c
+- cdef Py_ssize_t sz
+-
+- _check_closed(self, True)
+- if isinstance(optval, unicode):
+- raise TypeError("unicode not allowed, use setsockopt_string")
+-
+- if option in zmq.constants.bytes_sockopts:
+- if not isinstance(optval, bytes):
+- raise TypeError('expected bytes, got: %r' % optval)
+- optval_c = PyBytes_AsString(optval)
+- sz = PyBytes_Size(optval)
+- with nogil:
+- rc = zmq_setsockopt(
+- self.handle, option,
+- optval_c, sz
+- )
+- elif option in zmq.constants.int64_sockopts:
+- if not isinstance(optval, int):
+- raise TypeError('expected int, got: %r' % optval)
+- optval_int64_c = optval
+- with nogil:
+- rc = zmq_setsockopt(
+- self.handle, option,
+- &optval_int64_c, sizeof(int64_t)
+- )
+- else:
+- # default is to assume int, which is what most new sockopts will be
+- # this lets pyzmq work with newer libzmq which may add constants
+- # pyzmq has not yet added, rather than artificially raising. Invalid
+- # sockopts will still raise just the same, but it will be libzmq doing
+- # the raising.
+- if not isinstance(optval, int):
+- raise TypeError('expected int, got: %r' % optval)
+- optval_int_c = optval
+- with nogil:
+- rc = zmq_setsockopt(
+- self.handle, option,
+- &optval_int_c, sizeof(int)
+- )
+-
+- _check_rc(rc)
+-
+- def get(self, int option):
+- """s.get(option)
+-
+- Get the value of a socket option.
+-
+- See the 0MQ API documentation for details on specific options.
+-
+- Parameters
+- ----------
+- option : int
+- The option to get. Available values will depend on your
+- version of libzmq. Examples include::
+-
+- zmq.IDENTITY, HWM, LINGER, FD, EVENTS
+-
+- Returns
+- -------
+- optval : int or bytes
+- The value of the option as a bytestring or int.
+- """
+- cdef int64_t optval_int64_c
+- cdef int optval_int_c
+- cdef fd_t optval_fd_c
+- cdef char identity_str_c [255]
+- cdef size_t sz
+- cdef int rc
+-
+- _check_closed(self, True)
+-
+- if option in zmq.constants.bytes_sockopts:
+- sz = 255
+- with nogil:
+- rc = zmq_getsockopt(self.handle, option, <void *>identity_str_c, &sz)
+- _check_rc(rc)
+- result = PyBytes_FromStringAndSize(<char *>identity_str_c, sz)
+- elif option in zmq.constants.int64_sockopts:
+- sz = sizeof(int64_t)
+- with nogil:
+- rc = zmq_getsockopt(self.handle, option, <void *>&optval_int64_c, &sz)
+- _check_rc(rc)
+- result = optval_int64_c
+- elif option == ZMQ_FD:
+- sz = sizeof(fd_t)
+- with nogil:
+- rc = zmq_getsockopt(self.handle, option, <void *>&optval_fd_c, &sz)
+- _check_rc(rc)
+- result = optval_fd_c
+- else:
+- # default is to assume int, which is what most new sockopts will be
+- # this lets pyzmq work with newer libzmq which may add constants
+- # pyzmq has not yet added, rather than artificially raising. Invalid
+- # sockopts will still raise just the same, but it will be libzmq doing
+- # the raising.
+- sz = sizeof(int)
+- with nogil:
+- rc = zmq_getsockopt(self.handle, option, <void *>&optval_int_c, &sz)
+- _check_rc(rc)
+- result = optval_int_c
+-
+- return result
+-
+- def bind(self, addr):
+- """s.bind(addr)
+-
+- Bind the socket to an address.
+-
+- This causes the socket to listen on a network port. Sockets on the
+- other side of this connection will use ``Socket.connect(addr)`` to
+- connect to this socket.
+-
+- Parameters
+- ----------
+- addr : str
+- The address string. This has the form 'protocol://interface:port',
+- for example 'tcp://127.0.0.1:5555'. Protocols supported include
+- tcp, udp, pgm, epgm, inproc and ipc. If the address is unicode, it is
+- encoded to utf-8 first.
+- """
+- cdef int rc
+- cdef char* c_addr
+-
+- _check_closed(self, True)
+- if isinstance(addr, unicode):
+- addr = addr.encode('utf-8')
+- if not isinstance(addr, bytes):
+- raise TypeError('expected str, got: %r' % addr)
+- c_addr = addr
+- rc = zmq_bind(self.handle, c_addr)
+- if rc != 0:
+- if IPC_PATH_MAX_LEN and zmq_errno() == ENAMETOOLONG:
+- # py3compat: addr is bytes, but msg wants str
+- if str is unicode:
+- addr = addr.decode('utf-8', 'replace')
+- path = addr.split('://', 1)[-1]
+- msg = ('ipc path "{0}" is longer than {1} '
+- 'characters (sizeof(sockaddr_un.sun_path)). '
+- 'zmq.IPC_PATH_MAX_LEN constant can be used '
+- 'to check addr length (if it is defined).'
+- .format(path, IPC_PATH_MAX_LEN))
+- raise ZMQError(msg=msg)
+- _check_rc(rc)
+-
+- def connect(self, addr):
+- """s.connect(addr)
+-
+- Connect to a remote 0MQ socket.
+-
+- Parameters
+- ----------
+- addr : str
+- The address string. This has the form 'protocol://interface:port',
+- for example 'tcp://127.0.0.1:5555'. Protocols supported are
+- tcp, upd, pgm, inproc and ipc. If the address is unicode, it is
+- encoded to utf-8 first.
+- """
+- cdef int rc
+- cdef char* c_addr
+-
+- _check_closed(self, True)
+- if isinstance(addr, unicode):
+- addr = addr.encode('utf-8')
+- if not isinstance(addr, bytes):
+- raise TypeError('expected str, got: %r' % addr)
+- c_addr = addr
+-
+- rc = zmq_connect(self.handle, c_addr)
+- if rc != 0:
+- raise ZMQError()
+-
+- def unbind(self, addr):
+- """s.unbind(addr)
+-
+- Unbind from an address (undoes a call to bind).
+-
+- This feature requires libzmq-3
+-
+- Parameters
+- ----------
+- addr : str
+- The address string. This has the form 'protocol://interface:port',
+- for example 'tcp://127.0.0.1:5555'. Protocols supported are
+- tcp, upd, pgm, inproc and ipc. If the address is unicode, it is
+- encoded to utf-8 first.
+- """
+- cdef int rc
+- cdef char* c_addr
+-
+- if ZMQ_VERSION_MAJOR < 3:
+- raise NotImplementedError("unbind requires libzmq >= 3.0, have %s" % zmq.zmq_version())
+-
+-
+- _check_closed(self, True)
+- if isinstance(addr, unicode):
+- addr = addr.encode('utf-8')
+- if not isinstance(addr, bytes):
+- raise TypeError('expected str, got: %r' % addr)
+- c_addr = addr
+-
+- rc = zmq_unbind(self.handle, c_addr)
+- if rc != 0:
+- raise ZMQError()
+-
+- def disconnect(self, addr):
+- """s.disconnect(addr)
+-
+- Disconnect from a remote 0MQ socket (undoes a call to connect).
+-
+- This feature requires libzmq-3
+-
+- Parameters
+- ----------
+- addr : str
+- The address string. This has the form 'protocol://interface:port',
+- for example 'tcp://127.0.0.1:5555'. Protocols supported are
+- tcp, upd, pgm, inproc and ipc. If the address is unicode, it is
+- encoded to utf-8 first.
+- """
+- cdef int rc
+- cdef char* c_addr
+-
+- if ZMQ_VERSION_MAJOR < 3:
+- raise NotImplementedError("disconnect requires libzmq >= 3.0, have %s" % zmq.zmq_version())
+-
+- _check_closed(self, True)
+- if isinstance(addr, unicode):
+- addr = addr.encode('utf-8')
+- if not isinstance(addr, bytes):
+- raise TypeError('expected str, got: %r' % addr)
+- c_addr = addr
+-
+- rc = zmq_disconnect(self.handle, c_addr)
+- if rc != 0:
+- raise ZMQError()
+-
+- #-------------------------------------------------------------------------
+- # Sending and receiving messages
+- #-------------------------------------------------------------------------
+-
+- cpdef object send(self, object data, int flags=0, copy=True, track=False):
+- """s.send(data, flags=0, copy=True, track=False)
+-
+- Send a message on this socket.
+-
+- This queues the message to be sent by the IO thread at a later time.
+-
+- Parameters
+- ----------
+- data : object, str, Frame
+- The content of the message.
+- flags : int
+- Any supported flag: NOBLOCK, SNDMORE.
+- copy : bool
+- Should the message be sent in a copying or non-copying manner.
+- track : bool
+- Should the message be tracked for notification that ZMQ has
+- finished with it? (ignored if copy=True)
+-
+- Returns
+- -------
+- None : if `copy` or not track
+- None if message was sent, raises an exception otherwise.
+- MessageTracker : if track and not copy
+- a MessageTracker object, whose `pending` property will
+- be True until the send is completed.
+-
+- Raises
+- ------
+- TypeError
+- If a unicode object is passed
+- ValueError
+- If `track=True`, but an untracked Frame is passed.
+- ZMQError
+- If the send does not succeed for any reason.
+-
+- """
+- _check_closed(self, True)
+-
+- if isinstance(data, unicode):
+- raise TypeError("unicode not allowed, use send_unicode")
+-
+- if copy:
+- # msg.bytes never returns the input data object
+- # it is always a copy, but always the same copy
+- if isinstance(data, Frame):
+- data = data.buffer
+- return _send_copy(self.handle, data, flags)
+- else:
+- if isinstance(data, Frame):
+- if track and not data.tracker:
+- raise ValueError('Not a tracked message')
+- msg = data
+- else:
+- msg = Frame(data, track=track)
+- return _send_frame(self.handle, msg, flags)
+-
+- cpdef object recv(self, int flags=0, copy=True, track=False):
+- """s.recv(flags=0, copy=True, track=False)
+-
+- Receive a message.
+-
+- Parameters
+- ----------
+- flags : int
+- Any supported flag: NOBLOCK. If NOBLOCK is set, this method
+- will raise a ZMQError with EAGAIN if a message is not ready.
+- If NOBLOCK is not set, then this method will block until a
+- message arrives.
+- copy : bool
+- Should the message be received in a copying or non-copying manner?
+- If False a Frame object is returned, if True a string copy of
+- message is returned.
+- track : bool
+- Should the message be tracked for notification that ZMQ has
+- finished with it? (ignored if copy=True)
+-
+- Returns
+- -------
+- msg : bytes, Frame
+- The received message frame. If `copy` is False, then it will be a Frame,
+- otherwise it will be bytes.
+-
+- Raises
+- ------
+- ZMQError
+- for any of the reasons zmq_msg_recv might fail.
+- """
+- _check_closed(self, True)
+-
+- if copy:
+- return _recv_copy(self.handle, flags)
+- else:
+- frame = _recv_frame(self.handle, flags, track)
+- frame.more = self.getsockopt(zmq.RCVMORE)
+- return frame
+-
+-
+-__all__ = ['Socket', 'IPC_PATH_MAX_LEN']
+diff --git a/zmq/core/stopwatch.pxd b/zmq/core/stopwatch.pxd
+deleted file mode 100644
+index 5d56166..0000000
+--- a/zmq/core/stopwatch.pxd
++++ /dev/null
+@@ -1,31 +0,0 @@
+-"""0MQ Stopwatch class declaration."""
+-
+-#
+-# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
+-#
+-# This file is part of pyzmq.
+-#
+-# pyzmq is free software; you can redistribute it and/or modify it under
+-# the terms of the Lesser GNU General Public License as published by
+-# the Free Software Foundation; either version 3 of the License, or
+-# (at your option) any later version.
+-#
+-# pyzmq is distributed in the hope that it will be useful,
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-# Lesser GNU General Public License for more details.
+-#
+-# You should have received a copy of the Lesser GNU General Public License
+-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+-#
+-
+-#-----------------------------------------------------------------------------
+-# Code
+-#-----------------------------------------------------------------------------
+-
+-
+-cdef class Stopwatch:
+- """A simple stopwatch based on zmq_stopwatch_start/stop."""
+-
+- cdef void *watch # The C handle for the underlying zmq object
+-
+diff --git a/zmq/core/stopwatch.pyx b/zmq/core/stopwatch.pyx
+deleted file mode 100644
+index 6d2fd61..0000000
+--- a/zmq/core/stopwatch.pyx
++++ /dev/null
+@@ -1,90 +0,0 @@
+-"""0MQ Stopwatch class."""
+-
+-#
+-# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
+-#
+-# This file is part of pyzmq.
+-#
+-# pyzmq is free software; you can redistribute it and/or modify it under
+-# the terms of the Lesser GNU General Public License as published by
+-# the Free Software Foundation; either version 3 of the License, or
+-# (at your option) any later version.
+-#
+-# pyzmq is distributed in the hope that it will be useful,
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-# Lesser GNU General Public License for more details.
+-#
+-# You should have received a copy of the Lesser GNU General Public License
+-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+-#
+-
+-#-----------------------------------------------------------------------------
+-# Imports
+-#-----------------------------------------------------------------------------
+-
+-from libzmq cimport zmq_stopwatch_start, zmq_stopwatch_stop, zmq_sleep
+-
+-from zmq.error import ZMQError
+-
+-#-----------------------------------------------------------------------------
+-# Code
+-#-----------------------------------------------------------------------------
+-
+-cdef class Stopwatch:
+- """Stopwatch()
+-
+- A simple stopwatch based on zmq_stopwatch_start/stop.
+-
+- This class should be used for benchmarking and timing 0MQ code.
+- """
+-
+- def __cinit__(self):
+- self.watch = NULL
+-
+- def __dealloc__(self):
+- try:
+- self.stop()
+- except ZMQError:
+- pass
+-
+- def start(self):
+- """s.start()
+-
+- Start the stopwatch.
+- """
+- if self.watch == NULL:
+- with nogil:
+- self.watch = zmq_stopwatch_start()
+- else:
+- raise ZMQError('Stopwatch is already runing.')
+-
+- def stop(self):
+- """s.stop()
+-
+- Stop the stopwatch.
+-
+- Returns
+- -------
+- t : unsigned long int
+- the number of microseconds since ``start()`` was called.
+- """
+- cdef unsigned long time
+- if self.watch == NULL:
+- raise ZMQError('Must start the Stopwatch before calling stop.')
+- else:
+- with nogil:
+- time = zmq_stopwatch_stop(self.watch)
+- self.watch = NULL
+- return time
+-
+- def sleep(self, int seconds):
+- """s.sleep(seconds)
+-
+- Sleep for an integer number of seconds.
+- """
+- with nogil:
+- zmq_sleep(seconds)
+-
+-
+-__all__ = ['Stopwatch']
+diff --git a/zmq/devices/__init__.py b/zmq/devices/__init__.py
+index b5c8eb3..dcae13d 100644
+--- a/zmq/devices/__init__.py
++++ b/zmq/devices/__init__.py
+@@ -14,11 +14,12 @@
+ #-----------------------------------------------------------------------------
+
+ from zmq import device
+-from zmq.devices import basedevice, proxydevice, monitoredqueue, monitoredqueuedevice
++from zmq.devices import basedevice, proxydevice, monitoredqueuedevice
++from zmq.devices import _zmonitoredqueue as monitoredqueue
+
+ from zmq.devices.basedevice import *
+ from zmq.devices.proxydevice import *
+-from zmq.devices.monitoredqueue import *
++from zmq.devices._zmonitoredqueue import *
+ from zmq.devices.monitoredqueuedevice import *
+
+ __all__ = ['device']
+diff --git a/zmq/devices/_zmonitoredqueue.pxd b/zmq/devices/_zmonitoredqueue.pxd
+new file mode 100644
+index 0000000..e04354a
+--- /dev/null
++++ b/zmq/devices/_zmonitoredqueue.pxd
+@@ -0,0 +1,166 @@
++"""MonitoredQueue class declarations.
++
++Authors
++-------
++* MinRK
++* Brian Granger
++"""
++
++#
++# Copyright (c) 2010 Min Ragan-Kelley, Brian Granger
++#
++# This file is part of pyzmq, but is derived and adapted from zmq_queue.cpp
++# originally from libzmq-2.1.6, used under LGPLv3
++#
++# pyzmq is free software; you can redistribute it and/or modify it under
++# the terms of the Lesser GNU General Public License as published by
++# the Free Software Foundation; either version 3 of the License, or
++# (at your option) any later version.
++#
++# pyzmq is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++# Lesser GNU General Public License for more details.
++#
++# You should have received a copy of the Lesser GNU General Public License
++# along with this program. If not, see <http://www.gnu.org/licenses/>.
++#
++
++#-----------------------------------------------------------------------------
++# Imports
++#-----------------------------------------------------------------------------
++
++from libzmq cimport *
++
++#-----------------------------------------------------------------------------
++# MonitoredQueue C functions
++#-----------------------------------------------------------------------------
++
++cdef inline int _relay(void *insocket_, void *outsocket_, void *sidesocket_,
++ zmq_msg_t msg, zmq_msg_t side_msg, zmq_msg_t id_msg,
++ bint swap_ids) nogil:
++ cdef int rc
++ cdef int64_t flag_2
++ cdef int flag_3
++ cdef int flags
++ cdef bint more
++ cdef size_t flagsz
++ cdef void * flag_ptr
++
++ if ZMQ_VERSION_MAJOR < 3:
++ flagsz = sizeof (int64_t)
++ flag_ptr = &flag_2
++ else:
++ flagsz = sizeof (int)
++ flag_ptr = &flag_3
++
++ if swap_ids:# both router, must send second identity first
++ # recv two ids into msg, id_msg
++ rc = zmq_msg_recv(&msg, insocket_, 0)
++ rc = zmq_msg_recv(&id_msg, insocket_, 0)
++
++ # send second id (id_msg) first
++ #!!!! always send a copy before the original !!!!
++ rc = zmq_msg_copy(&side_msg, &id_msg)
++ rc = zmq_msg_send(&side_msg, outsocket_, ZMQ_SNDMORE)
++ rc = zmq_msg_send(&id_msg, sidesocket_, ZMQ_SNDMORE)
++ # send first id (msg) second
++ rc = zmq_msg_copy(&side_msg, &msg)
++ rc = zmq_msg_send(&side_msg, outsocket_, ZMQ_SNDMORE)
++ rc = zmq_msg_send(&msg, sidesocket_, ZMQ_SNDMORE)
++ if rc < 0:
++ return rc
++ while (True):
++ rc = zmq_msg_recv(&msg, insocket_, 0)
++ # assert (rc == 0)
++ rc = zmq_getsockopt (insocket_, ZMQ_RCVMORE, flag_ptr, &flagsz)
++ flags = 0
++ if ZMQ_VERSION_MAJOR < 3:
++ if flag_2:
++ flags |= ZMQ_SNDMORE
++ else:
++ if flag_3:
++ flags |= ZMQ_SNDMORE
++ # LABEL has been removed:
++ # rc = zmq_getsockopt (insocket_, ZMQ_RCVLABEL, flag_ptr, &flagsz)
++ # if flag_3:
++ # flags |= ZMQ_SNDLABEL
++ # assert (rc == 0)
++
++ rc = zmq_msg_copy(&side_msg, &msg)
++ if flags:
++ rc = zmq_msg_send(&side_msg, outsocket_, flags)
++ # only SNDMORE for side-socket
++ rc = zmq_msg_send(&msg, sidesocket_, ZMQ_SNDMORE)
++ else:
++ rc = zmq_msg_send(&side_msg, outsocket_, 0)
++ rc = zmq_msg_send(&msg, sidesocket_, 0)
++ break
++ return rc
++
++# the MonitoredQueue C function, adapted from zmq::queue.cpp :
++cdef inline int c_monitored_queue (void *insocket_, void *outsocket_,
++ void *sidesocket_, zmq_msg_t *in_msg_ptr,
++ zmq_msg_t *out_msg_ptr, int swap_ids) nogil:
++ """The actual C function for a monitored queue device.
++
++ See ``monitored_queue()`` for details.
++ """
++
++ cdef zmq_msg_t msg
++ cdef int rc = zmq_msg_init (&msg)
++ cdef zmq_msg_t id_msg
++ rc = zmq_msg_init (&id_msg)
++ cdef zmq_msg_t side_msg
++ rc = zmq_msg_init (&side_msg)
++ # assert (rc == 0)
++
++
++ cdef zmq_pollitem_t items [2]
++ items [0].socket = insocket_
++ items [0].fd = 0
++ items [0].events = ZMQ_POLLIN
++ items [0].revents = 0
++ items [1].socket = outsocket_
++ items [1].fd = 0
++ items [1].events = ZMQ_POLLIN
++ items [1].revents = 0
++ # I don't think sidesocket should be polled?
++ # items [2].socket = sidesocket_
++ # items [2].fd = 0
++ # items [2].events = ZMQ_POLLIN
++ # items [2].revents = 0
++
++ while (True):
++
++ # // Wait while there are either requests or replies to process.
++ rc = zmq_poll (&items [0], 2, -1)
++ if rc < 0:
++ return rc
++ # // The algorithm below asumes ratio of request and replies processed
++ # // under full load to be 1:1. Although processing requests replies
++ # // first is tempting it is suspectible to DoS attacks (overloading
++ # // the system with unsolicited replies).
++ #
++ # // Process a request.
++ if (items [0].revents & ZMQ_POLLIN):
++ # send in_prefix to side socket
++ rc = zmq_msg_copy(&side_msg, in_msg_ptr)
++ rc = zmq_msg_send(&side_msg, sidesocket_, ZMQ_SNDMORE)
++ if rc < 0:
++ return rc
++ # relay the rest of the message
++ rc = _relay(insocket_, outsocket_, sidesocket_, msg, side_msg, id_msg, swap_ids)
++ if rc < 0:
++ return rc
++ if (items [1].revents & ZMQ_POLLIN):
++ # send out_prefix to side socket
++ rc = zmq_msg_copy(&side_msg, out_msg_ptr)
++ rc = zmq_msg_send(&side_msg, sidesocket_, ZMQ_SNDMORE)
++ if rc < 0:
++ return rc
++ # relay the rest of the message
++ rc = _relay(outsocket_, insocket_, sidesocket_, msg, side_msg, id_msg, swap_ids)
++ if rc < 0:
++ return rc
++ return 0
+diff --git a/zmq/devices/_zmonitoredqueue.pyx b/zmq/devices/_zmonitoredqueue.pyx
+new file mode 100644
+index 0000000..a74ae8e
+--- /dev/null
++++ b/zmq/devices/_zmonitoredqueue.pyx
+@@ -0,0 +1,108 @@
++"""MonitoredQueue classes and functions.
++
++Authors
++-------
++* MinRK
++* Brian Granger
++"""
++
++#-----------------------------------------------------------------------------
++# Copyright (c) 2010-2012 Brian Granger, Min Ragan-Kelley
++#
++# This file is part of pyzmq
++#
++# Distributed under the terms of the New BSD License. The full license is in
++# the file COPYING.BSD, distributed as part of this software.
++#-----------------------------------------------------------------------------
++
++#-----------------------------------------------------------------------------
++# Imports
++#-----------------------------------------------------------------------------
++
++cdef extern from "Python.h":
++ ctypedef int Py_ssize_t
++
++from libc.string cimport memcpy
++
++from buffers cimport asbuffer_r
++from libzmq cimport *
++
++from zmq.core._zsocket cimport Socket
++from zmq.core.checkrc cimport _check_rc
++
++from zmq import ROUTER, ZMQError
++
++#-----------------------------------------------------------------------------
++# MonitoredQueue functions
++#-----------------------------------------------------------------------------
++
++
++def monitored_queue(Socket in_socket, Socket out_socket, Socket mon_socket,
++ bytes in_prefix=b'in', bytes out_prefix=b'out'):
++ """monitored_queue(in_socket, out_socket, mon_socket,
++ in_prefix='in', out_prefix='out')
++
++ Start a monitored queue device.
++
++ A monitored queue behaves just like a zmq QUEUE device as far as in_socket
++ and out_socket are concerned, except that all messages *also* go out on
++ mon_socket. mon_socket also prefixes the messages coming from each with a
++ prefix, by default 'in' and 'out', so all messages sent by mon_socket are
++ multipart.
++
++ The only difference between this and a QUEUE as far as in/out are
++ concerned is that it works with two ROUTER sockets by swapping the IDENT
++ prefixes.
++
++ Parameters
++ ----------
++ in_socket : Socket
++ One of the sockets to the Queue. Its messages will be prefixed with
++ 'in'.
++ out_socket : Socket
++ One of the sockets to the Queue. Its messages will be prefixed with
++ 'out'. The only difference between in/out socket is this prefix.
++ mon_socket : Socket
++ This socket sends out every message received by each of the others
++ with an in/out prefix specifying which one it was.
++ in_prefix : str
++ Prefix added to broadcast messages from in_socket.
++ out_prefix : str
++ Prefix added to broadcast messages from out_socket.
++ """
++
++ cdef void *ins=in_socket.handle
++ cdef void *outs=out_socket.handle
++ cdef void *mons=mon_socket.handle
++ cdef zmq_msg_t in_msg
++ cdef zmq_msg_t out_msg
++ cdef bint swap_ids
++ cdef char *msg_c = NULL
++ cdef Py_ssize_t msg_c_len
++ cdef int rc
++
++ # force swap_ids if both ROUTERs
++ swap_ids = (in_socket.socket_type == ROUTER and
++ out_socket.socket_type == ROUTER)
++
++ # build zmq_msg objects from str prefixes
++ asbuffer_r(in_prefix, <void **>&msg_c, &msg_c_len)
++ with nogil:
++ rc = zmq_msg_init_size(&in_msg, msg_c_len)
++ _check_rc(rc)
++
++ with nogil:
++ memcpy(zmq_msg_data(&in_msg), msg_c, zmq_msg_size(&in_msg))
++
++ asbuffer_r(out_prefix, <void **>&msg_c, &msg_c_len)
++
++ with nogil:
++ rc = zmq_msg_init_size(&out_msg, msg_c_len)
++ _check_rc(rc)
++
++ with nogil:
++ memcpy(zmq_msg_data(&out_msg), msg_c, zmq_msg_size(&out_msg))
++ rc = c_monitored_queue(ins, outs, mons, &in_msg, &out_msg, swap_ids)
++ return rc
++
++__all__ = ['monitored_queue']
+diff --git a/zmq/devices/basedevice.py b/zmq/devices/basedevice.py
+index f65ba1f..4b2c42b 100644
+--- a/zmq/devices/basedevice.py
++++ b/zmq/devices/basedevice.py
+@@ -20,8 +20,15 @@ Authors
+ #-----------------------------------------------------------------------------
+
+ import time
+-from threading import Thread
+-from multiprocessing import Process
++try:
++ from threading import Thread
++except ImportError:
++ Thread = None
++
++try:
++ from multiprocessing import Process
++except ImportError:
++ Process = None
+
+ from zmq import device, QUEUE, Context
+
+diff --git a/zmq/devices/monitoredqueue.pxd b/zmq/devices/monitoredqueue.pxd
+deleted file mode 100644
+index e04354a..0000000
+--- a/zmq/devices/monitoredqueue.pxd
++++ /dev/null
+@@ -1,166 +0,0 @@
+-"""MonitoredQueue class declarations.
+-
+-Authors
+--------
+-* MinRK
+-* Brian Granger
+-"""
+-
+-#
+-# Copyright (c) 2010 Min Ragan-Kelley, Brian Granger
+-#
+-# This file is part of pyzmq, but is derived and adapted from zmq_queue.cpp
+-# originally from libzmq-2.1.6, used under LGPLv3
+-#
+-# pyzmq is free software; you can redistribute it and/or modify it under
+-# the terms of the Lesser GNU General Public License as published by
+-# the Free Software Foundation; either version 3 of the License, or
+-# (at your option) any later version.
+-#
+-# pyzmq is distributed in the hope that it will be useful,
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-# Lesser GNU General Public License for more details.
+-#
+-# You should have received a copy of the Lesser GNU General Public License
+-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+-#
+-
+-#-----------------------------------------------------------------------------
+-# Imports
+-#-----------------------------------------------------------------------------
+-
+-from libzmq cimport *
+-
+-#-----------------------------------------------------------------------------
+-# MonitoredQueue C functions
+-#-----------------------------------------------------------------------------
+-
+-cdef inline int _relay(void *insocket_, void *outsocket_, void *sidesocket_,
+- zmq_msg_t msg, zmq_msg_t side_msg, zmq_msg_t id_msg,
+- bint swap_ids) nogil:
+- cdef int rc
+- cdef int64_t flag_2
+- cdef int flag_3
+- cdef int flags
+- cdef bint more
+- cdef size_t flagsz
+- cdef void * flag_ptr
+-
+- if ZMQ_VERSION_MAJOR < 3:
+- flagsz = sizeof (int64_t)
+- flag_ptr = &flag_2
+- else:
+- flagsz = sizeof (int)
+- flag_ptr = &flag_3
+-
+- if swap_ids:# both router, must send second identity first
+- # recv two ids into msg, id_msg
+- rc = zmq_msg_recv(&msg, insocket_, 0)
+- rc = zmq_msg_recv(&id_msg, insocket_, 0)
+-
+- # send second id (id_msg) first
+- #!!!! always send a copy before the original !!!!
+- rc = zmq_msg_copy(&side_msg, &id_msg)
+- rc = zmq_msg_send(&side_msg, outsocket_, ZMQ_SNDMORE)
+- rc = zmq_msg_send(&id_msg, sidesocket_, ZMQ_SNDMORE)
+- # send first id (msg) second
+- rc = zmq_msg_copy(&side_msg, &msg)
+- rc = zmq_msg_send(&side_msg, outsocket_, ZMQ_SNDMORE)
+- rc = zmq_msg_send(&msg, sidesocket_, ZMQ_SNDMORE)
+- if rc < 0:
+- return rc
+- while (True):
+- rc = zmq_msg_recv(&msg, insocket_, 0)
+- # assert (rc == 0)
+- rc = zmq_getsockopt (insocket_, ZMQ_RCVMORE, flag_ptr, &flagsz)
+- flags = 0
+- if ZMQ_VERSION_MAJOR < 3:
+- if flag_2:
+- flags |= ZMQ_SNDMORE
+- else:
+- if flag_3:
+- flags |= ZMQ_SNDMORE
+- # LABEL has been removed:
+- # rc = zmq_getsockopt (insocket_, ZMQ_RCVLABEL, flag_ptr, &flagsz)
+- # if flag_3:
+- # flags |= ZMQ_SNDLABEL
+- # assert (rc == 0)
+-
+- rc = zmq_msg_copy(&side_msg, &msg)
+- if flags:
+- rc = zmq_msg_send(&side_msg, outsocket_, flags)
+- # only SNDMORE for side-socket
+- rc = zmq_msg_send(&msg, sidesocket_, ZMQ_SNDMORE)
+- else:
+- rc = zmq_msg_send(&side_msg, outsocket_, 0)
+- rc = zmq_msg_send(&msg, sidesocket_, 0)
+- break
+- return rc
+-
+-# the MonitoredQueue C function, adapted from zmq::queue.cpp :
+-cdef inline int c_monitored_queue (void *insocket_, void *outsocket_,
+- void *sidesocket_, zmq_msg_t *in_msg_ptr,
+- zmq_msg_t *out_msg_ptr, int swap_ids) nogil:
+- """The actual C function for a monitored queue device.
+-
+- See ``monitored_queue()`` for details.
+- """
+-
+- cdef zmq_msg_t msg
+- cdef int rc = zmq_msg_init (&msg)
+- cdef zmq_msg_t id_msg
+- rc = zmq_msg_init (&id_msg)
+- cdef zmq_msg_t side_msg
+- rc = zmq_msg_init (&side_msg)
+- # assert (rc == 0)
+-
+-
+- cdef zmq_pollitem_t items [2]
+- items [0].socket = insocket_
+- items [0].fd = 0
+- items [0].events = ZMQ_POLLIN
+- items [0].revents = 0
+- items [1].socket = outsocket_
+- items [1].fd = 0
+- items [1].events = ZMQ_POLLIN
+- items [1].revents = 0
+- # I don't think sidesocket should be polled?
+- # items [2].socket = sidesocket_
+- # items [2].fd = 0
+- # items [2].events = ZMQ_POLLIN
+- # items [2].revents = 0
+-
+- while (True):
+-
+- # // Wait while there are either requests or replies to process.
+- rc = zmq_poll (&items [0], 2, -1)
+- if rc < 0:
+- return rc
+- # // The algorithm below asumes ratio of request and replies processed
+- # // under full load to be 1:1. Although processing requests replies
+- # // first is tempting it is suspectible to DoS attacks (overloading
+- # // the system with unsolicited replies).
+- #
+- # // Process a request.
+- if (items [0].revents & ZMQ_POLLIN):
+- # send in_prefix to side socket
+- rc = zmq_msg_copy(&side_msg, in_msg_ptr)
+- rc = zmq_msg_send(&side_msg, sidesocket_, ZMQ_SNDMORE)
+- if rc < 0:
+- return rc
+- # relay the rest of the message
+- rc = _relay(insocket_, outsocket_, sidesocket_, msg, side_msg, id_msg, swap_ids)
+- if rc < 0:
+- return rc
+- if (items [1].revents & ZMQ_POLLIN):
+- # send out_prefix to side socket
+- rc = zmq_msg_copy(&side_msg, out_msg_ptr)
+- rc = zmq_msg_send(&side_msg, sidesocket_, ZMQ_SNDMORE)
+- if rc < 0:
+- return rc
+- # relay the rest of the message
+- rc = _relay(outsocket_, insocket_, sidesocket_, msg, side_msg, id_msg, swap_ids)
+- if rc < 0:
+- return rc
+- return 0
+diff --git a/zmq/devices/monitoredqueue.pyx b/zmq/devices/monitoredqueue.pyx
+deleted file mode 100644
+index 65db882..0000000
+--- a/zmq/devices/monitoredqueue.pyx
++++ /dev/null
+@@ -1,108 +0,0 @@
+-"""MonitoredQueue classes and functions.
+-
+-Authors
+--------
+-* MinRK
+-* Brian Granger
+-"""
+-
+-#-----------------------------------------------------------------------------
+-# Copyright (c) 2010-2012 Brian Granger, Min Ragan-Kelley
+-#
+-# This file is part of pyzmq
+-#
+-# Distributed under the terms of the New BSD License. The full license is in
+-# the file COPYING.BSD, distributed as part of this software.
+-#-----------------------------------------------------------------------------
+-
+-#-----------------------------------------------------------------------------
+-# Imports
+-#-----------------------------------------------------------------------------
+-
+-cdef extern from "Python.h":
+- ctypedef int Py_ssize_t
+-
+-from libc.string cimport memcpy
+-
+-from buffers cimport asbuffer_r
+-from libzmq cimport *
+-
+-from zmq.core.socket cimport Socket
+-from zmq.core.checkrc cimport _check_rc
+-
+-from zmq import ROUTER, ZMQError
+-
+-#-----------------------------------------------------------------------------
+-# MonitoredQueue functions
+-#-----------------------------------------------------------------------------
+-
+-
+-def monitored_queue(Socket in_socket, Socket out_socket, Socket mon_socket,
+- bytes in_prefix=b'in', bytes out_prefix=b'out'):
+- """monitored_queue(in_socket, out_socket, mon_socket,
+- in_prefix='in', out_prefix='out')
+-
+- Start a monitored queue device.
+-
+- A monitored queue behaves just like a zmq QUEUE device as far as in_socket
+- and out_socket are concerned, except that all messages *also* go out on
+- mon_socket. mon_socket also prefixes the messages coming from each with a
+- prefix, by default 'in' and 'out', so all messages sent by mon_socket are
+- multipart.
+-
+- The only difference between this and a QUEUE as far as in/out are
+- concerned is that it works with two ROUTER sockets by swapping the IDENT
+- prefixes.
+-
+- Parameters
+- ----------
+- in_socket : Socket
+- One of the sockets to the Queue. Its messages will be prefixed with
+- 'in'.
+- out_socket : Socket
+- One of the sockets to the Queue. Its messages will be prefixed with
+- 'out'. The only difference between in/out socket is this prefix.
+- mon_socket : Socket
+- This socket sends out every message received by each of the others
+- with an in/out prefix specifying which one it was.
+- in_prefix : str
+- Prefix added to broadcast messages from in_socket.
+- out_prefix : str
+- Prefix added to broadcast messages from out_socket.
+- """
+-
+- cdef void *ins=in_socket.handle
+- cdef void *outs=out_socket.handle
+- cdef void *mons=mon_socket.handle
+- cdef zmq_msg_t in_msg
+- cdef zmq_msg_t out_msg
+- cdef bint swap_ids
+- cdef char *msg_c = NULL
+- cdef Py_ssize_t msg_c_len
+- cdef int rc
+-
+- # force swap_ids if both ROUTERs
+- swap_ids = (in_socket.socket_type == ROUTER and
+- out_socket.socket_type == ROUTER)
+-
+- # build zmq_msg objects from str prefixes
+- asbuffer_r(in_prefix, <void **>&msg_c, &msg_c_len)
+- with nogil:
+- rc = zmq_msg_init_size(&in_msg, msg_c_len)
+- _check_rc(rc)
+-
+- with nogil:
+- memcpy(zmq_msg_data(&in_msg), msg_c, zmq_msg_size(&in_msg))
+-
+- asbuffer_r(out_prefix, <void **>&msg_c, &msg_c_len)
+-
+- with nogil:
+- rc = zmq_msg_init_size(&out_msg, msg_c_len)
+- _check_rc(rc)
+-
+- with nogil:
+- memcpy(zmq_msg_data(&out_msg), msg_c, zmq_msg_size(&out_msg))
+- rc = c_monitored_queue(ins, outs, mons, &in_msg, &out_msg, swap_ids)
+- return rc
+-
+-__all__ = ['monitored_queue']
+diff --git a/zmq/devices/monitoredqueuedevice.py b/zmq/devices/monitoredqueuedevice.py
+index a9f5c3f..422715c 100644
+--- a/zmq/devices/monitoredqueuedevice.py
++++ b/zmq/devices/monitoredqueuedevice.py
+@@ -24,7 +24,7 @@ import time
+
+ from zmq import ZMQError, PUB
+ from zmq.devices.proxydevice import ProxyBase, Proxy, ThreadProxy, ProcessProxy
+-from zmq.devices.monitoredqueue import monitored_queue
++from zmq.devices._zmonitoredqueue import monitored_queue
+
+ #-----------------------------------------------------------------------------
+ # Classes
+diff --git a/zmq/sugar/backend.py b/zmq/sugar/backend.py
+index ad07379..6f87c1b 100644
+--- a/zmq/sugar/backend.py
++++ b/zmq/sugar/backend.py
+@@ -23,8 +23,9 @@ try:
+ strerror, zmq_errno,
+ zmq_poll,
+ zmq_version_info,
+- constants,
++ _zconstants,
+ )
++ constants = _zconstants
+ except ImportError:
+ from zmq.cffi_core import (
+ Context,
+diff --git a/zmq/sugar/context.py b/zmq/sugar/context.py
+index bcc4686..f0f3325 100644
+--- a/zmq/sugar/context.py
++++ b/zmq/sugar/context.py
+@@ -128,4 +128,4 @@ class Context(ContextBase, AttributeSetter):
+ else:
+ del self.sockopts[opt]
+
+-__all__ = ['Context']
+\ No newline at end of file
++__all__ = ['Context']
+diff --git a/zmq/utils/_zinitthreads.pyx b/zmq/utils/_zinitthreads.pyx
+new file mode 100644
+index 0000000..6c57c9f
+--- /dev/null
++++ b/zmq/utils/_zinitthreads.pyx
+@@ -0,0 +1,23 @@
++"""Utility to initialize threads."""
++
++#-----------------------------------------------------------------------------
++# Copyright (c) 2010 Brian Granger, Min Ragan-Kelley
++#
++# Distributed under the terms of the New BSD License. The full license is in
++# the file COPYING.BSD, distributed as part of this software.
++#-----------------------------------------------------------------------------
++
++#-----------------------------------------------------------------------------
++# Imports
++#-----------------------------------------------------------------------------
++
++cdef extern from "Python.h":
++ cdef void PyEval_InitThreads()
++
++# It seems that in only *some* version of Python/Cython we need to call this
++# by hand to get threads initialized. Not clear why this is the case though.
++# If we don't have this, pyzmq will segfault.
++def init_threads():
++ PyEval_InitThreads()
++
++__all__ = ['init_threads']
+diff --git a/zmq/utils/_zrebuffer.pyx b/zmq/utils/_zrebuffer.pyx
+new file mode 100644
+index 0000000..ca240d3
+--- /dev/null
++++ b/zmq/utils/_zrebuffer.pyx
+@@ -0,0 +1,104 @@
++"""
++Utility for changing itemsize of memoryviews, and getting
++numpy arrays from byte-arrays that should be interpreted with a different
++itemsize.
++
++Authors
++-------
++* MinRK
++"""
++
++#-----------------------------------------------------------------------------
++# Copyright (c) 2010-2012 Brian Granger, Min Ragan-Kelley
++#
++# This file is part of pyzmq
++#
++# Distributed under the terms of the New BSD License. The full license is in
++# the file COPYING.BSD, distributed as part of this software.
++#-----------------------------------------------------------------------------
++
++from libc.stdlib cimport malloc
++from buffers cimport *
++
++cdef inline object _rebuffer(object obj, char * format, int itemsize):
++ """clobber the format & itemsize of a 1-D
++
++ This is the Python 3 model, but will work on Python >= 2.6. Currently,
++ we use it only on >= 3.0.
++ """
++ cdef Py_buffer view
++ cdef int flags = PyBUF_SIMPLE
++ cdef int mode = 0
++ # cdef Py_ssize_t *shape, *strides, *suboffsets
++
++ mode = check_buffer(obj)
++ if mode == 0:
++ raise TypeError("%r does not provide a buffer interface."%obj)
++
++ if mode == 3:
++ flags = PyBUF_ANY_CONTIGUOUS
++ if format:
++ flags |= PyBUF_FORMAT
++ PyObject_GetBuffer(obj, &view, flags)
++ assert view.ndim <= 1, "Can only reinterpret 1-D memoryviews"
++ assert view.len % itemsize == 0, "Buffer of length %i not divisible into items of size %i"%(view.len, itemsize)
++ # hack the format
++ view.ndim = 1
++ view.format = format
++ view.itemsize = itemsize
++ view.strides = <Py_ssize_t *>malloc(sizeof(Py_ssize_t))
++ view.strides[0] = itemsize
++ view.shape = <Py_ssize_t *>malloc(sizeof(Py_ssize_t))
++ view.shape[0] = view.len/itemsize
++ view.suboffsets = <Py_ssize_t *>malloc(sizeof(Py_ssize_t))
++ view.suboffsets[0] = 0
++ # for debug: make buffer writable, for zero-copy testing
++ # view.readonly = 0
++
++ return PyMemoryView_FromBuffer(&view)
++ else:
++ raise TypeError("This funciton is only for new-style buffer objects.")
++
++def rebuffer(obj, format, itemsize):
++ """Change the itemsize of a memoryview.
++
++ Only for 1D contiguous buffers.
++ """
++ return _rebuffer(obj, format, itemsize)
++
++def array_from_buffer(view, dtype, shape):
++ """Get a numpy array from a memoryview, regardless of the itemsize of the original
++ memoryview. This is important, because pyzmq does not send memoryview shape data
++ over the wire, so we need to change the memoryview itemsize before calling
++ asarray.
++ """
++ import numpy
++ A = numpy.array([],dtype=dtype)
++ ref = viewfromobject(A,0)
++ fmt = ref.format.encode()
++ buf = viewfromobject(view, 0)
++ buf = _rebuffer(view, fmt, ref.itemsize)
++ return numpy.asarray(buf, dtype=dtype).reshape(shape)
++
++def print_view_info(obj):
++ """simple utility for printing info on a new-style buffer object"""
++ cdef Py_buffer view
++ cdef int flags = PyBUF_ANY_CONTIGUOUS|PyBUF_FORMAT
++ cdef int mode = 0
++
++ mode = check_buffer(obj)
++ if mode == 0:
++ raise TypeError("%r does not provide a buffer interface."%obj)
++
++ if mode == 3:
++ PyObject_GetBuffer(obj, &view, flags)
++ print <Py_ssize_t>view.buf, view.len, view.format, view.ndim,
++ if view.ndim:
++ if view.shape:
++ print view.shape[0],
++ if view.strides:
++ print view.strides[0],
++ if view.suboffsets:
++ print view.suboffsets[0],
++ print
++
+\ No newline at end of file
+diff --git a/zmq/utils/initthreads.pyx b/zmq/utils/initthreads.pyx
+deleted file mode 100644
+index 6c57c9f..0000000
+--- a/zmq/utils/initthreads.pyx
++++ /dev/null
+@@ -1,23 +0,0 @@
+-"""Utility to initialize threads."""
+-
+-#-----------------------------------------------------------------------------
+-# Copyright (c) 2010 Brian Granger, Min Ragan-Kelley
+-#
+-# Distributed under the terms of the New BSD License. The full license is in
+-# the file COPYING.BSD, distributed as part of this software.
+-#-----------------------------------------------------------------------------
+-
+-#-----------------------------------------------------------------------------
+-# Imports
+-#-----------------------------------------------------------------------------
+-
+-cdef extern from "Python.h":
+- cdef void PyEval_InitThreads()
+-
+-# It seems that in only *some* version of Python/Cython we need to call this
+-# by hand to get threads initialized. Not clear why this is the case though.
+-# If we don't have this, pyzmq will segfault.
+-def init_threads():
+- PyEval_InitThreads()
+-
+-__all__ = ['init_threads']
+diff --git a/zmq/utils/rebuffer.pyx b/zmq/utils/rebuffer.pyx
+deleted file mode 100644
+index ca240d3..0000000
+--- a/zmq/utils/rebuffer.pyx
++++ /dev/null
+@@ -1,104 +0,0 @@
+-"""
+-Utility for changing itemsize of memoryviews, and getting
+-numpy arrays from byte-arrays that should be interpreted with a different
+-itemsize.
+-
+-Authors
+--------
+-* MinRK
+-"""
+-
+-#-----------------------------------------------------------------------------
+-# Copyright (c) 2010-2012 Brian Granger, Min Ragan-Kelley
+-#
+-# This file is part of pyzmq
+-#
+-# Distributed under the terms of the New BSD License. The full license is in
+-# the file COPYING.BSD, distributed as part of this software.
+-#-----------------------------------------------------------------------------
+-
+-from libc.stdlib cimport malloc
+-from buffers cimport *
+-
+-cdef inline object _rebuffer(object obj, char * format, int itemsize):
+- """clobber the format & itemsize of a 1-D
+-
+- This is the Python 3 model, but will work on Python >= 2.6. Currently,
+- we use it only on >= 3.0.
+- """
+- cdef Py_buffer view
+- cdef int flags = PyBUF_SIMPLE
+- cdef int mode = 0
+- # cdef Py_ssize_t *shape, *strides, *suboffsets
+-
+- mode = check_buffer(obj)
+- if mode == 0:
+- raise TypeError("%r does not provide a buffer interface."%obj)
+-
+- if mode == 3:
+- flags = PyBUF_ANY_CONTIGUOUS
+- if format:
+- flags |= PyBUF_FORMAT
+- PyObject_GetBuffer(obj, &view, flags)
+- assert view.ndim <= 1, "Can only reinterpret 1-D memoryviews"
+- assert view.len % itemsize == 0, "Buffer of length %i not divisible into items of size %i"%(view.len, itemsize)
+- # hack the format
+- view.ndim = 1
+- view.format = format
+- view.itemsize = itemsize
+- view.strides = <Py_ssize_t *>malloc(sizeof(Py_ssize_t))
+- view.strides[0] = itemsize
+- view.shape = <Py_ssize_t *>malloc(sizeof(Py_ssize_t))
+- view.shape[0] = view.len/itemsize
+- view.suboffsets = <Py_ssize_t *>malloc(sizeof(Py_ssize_t))
+- view.suboffsets[0] = 0
+- # for debug: make buffer writable, for zero-copy testing
+- # view.readonly = 0
+-
+- return PyMemoryView_FromBuffer(&view)
+- else:
+- raise TypeError("This funciton is only for new-style buffer objects.")
+-
+-def rebuffer(obj, format, itemsize):
+- """Change the itemsize of a memoryview.
+-
+- Only for 1D contiguous buffers.
+- """
+- return _rebuffer(obj, format, itemsize)
+-
+-def array_from_buffer(view, dtype, shape):
+- """Get a numpy array from a memoryview, regardless of the itemsize of the original
+- memoryview. This is important, because pyzmq does not send memoryview shape data
+- over the wire, so we need to change the memoryview itemsize before calling
+- asarray.
+- """
+- import numpy
+- A = numpy.array([],dtype=dtype)
+- ref = viewfromobject(A,0)
+- fmt = ref.format.encode()
+- buf = viewfromobject(view, 0)
+- buf = _rebuffer(view, fmt, ref.itemsize)
+- return numpy.asarray(buf, dtype=dtype).reshape(shape)
+-
+-def print_view_info(obj):
+- """simple utility for printing info on a new-style buffer object"""
+- cdef Py_buffer view
+- cdef int flags = PyBUF_ANY_CONTIGUOUS|PyBUF_FORMAT
+- cdef int mode = 0
+-
+- mode = check_buffer(obj)
+- if mode == 0:
+- raise TypeError("%r does not provide a buffer interface."%obj)
+-
+- if mode == 3:
+- PyObject_GetBuffer(obj, &view, flags)
+- print <Py_ssize_t>view.buf, view.len, view.format, view.ndim,
+- if view.ndim:
+- if view.shape:
+- print view.shape[0],
+- if view.strides:
+- print view.strides[0],
+- if view.suboffsets:
+- print view.suboffsets[0],
+- print
+-
+\ No newline at end of file
« no previous file with comments | « ports/python_modules/pyzmq/modules.list ('k') | ports/python_modules/pyzmq/pkg_info » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698