Chromium Code Reviews| 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/>. |
| ++# |
| ++ |
|
hamaji
2014/01/24 14:32:48
Why this file need to be added? Cannot we add a co
Matthew Turk
2014/01/28 19:39:20
Thanks for the tip, didn't know about it. But it
|
| ++#----------------------------------------------------------------------------- |
| ++# 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/>. |
| ++# |
| ++ |
|
hamaji
2014/01/24 14:32:48
ditto. Why added?
Matthew Turk
2014/01/28 19:39:20
Done.
|
| ++#----------------------------------------------------------------------------- |
| ++# 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], |
| ++ |
| +\ 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], |
| +- |
| +\ No newline at end of file |