1# coding: utf-8
2"""zmq Context class"""
3
4# Copyright (C) PyZMQ Developers
5# Distributed under the terms of the Modified BSD License.
6
7import weakref
8
9from ._cffi import C, ffi
10
11from .socket import *
12from .constants import *
13
14from zmq.error import ZMQError, _check_rc
15
16class Context(object):
17    _zmq_ctx = None
18    _iothreads = None
19    _closed = None
20    _sockets = None
21    _shadow = False
22
23    def __init__(self, io_threads=1, shadow=None):
24
25        if shadow:
26            self._zmq_ctx = ffi.cast("void *", shadow)
27            self._shadow = True
28        else:
29            self._shadow = False
30            if not io_threads >= 0:
31                raise ZMQError(EINVAL)
32
33            self._zmq_ctx = C.zmq_ctx_new()
34        if self._zmq_ctx == ffi.NULL:
35            raise ZMQError(C.zmq_errno())
36        if not shadow:
37            C.zmq_ctx_set(self._zmq_ctx, IO_THREADS, io_threads)
38        self._closed = False
39        self._sockets = set()
40
41    @property
42    def underlying(self):
43        """The address of the underlying libzmq context"""
44        return int(ffi.cast('size_t', self._zmq_ctx))
45
46    @property
47    def closed(self):
48        return self._closed
49
50    def _add_socket(self, socket):
51        ref = weakref.ref(socket)
52        self._sockets.add(ref)
53        return ref
54
55    def _rm_socket(self, ref):
56        if ref in self._sockets:
57            self._sockets.remove(ref)
58
59    def set(self, option, value):
60        """set a context option
61
62        see zmq_ctx_set
63        """
64        rc = C.zmq_ctx_set(self._zmq_ctx, option, value)
65        _check_rc(rc)
66
67    def get(self, option):
68        """get context option
69
70        see zmq_ctx_get
71        """
72        rc = C.zmq_ctx_get(self._zmq_ctx, option)
73        _check_rc(rc)
74        return rc
75
76    def term(self):
77        if self.closed:
78            return
79
80        C.zmq_ctx_destroy(self._zmq_ctx)
81
82        self._zmq_ctx = None
83        self._closed = True
84
85    def destroy(self, linger=None):
86        if self.closed:
87            return
88
89        sockets = self._sockets
90        self._sockets = set()
91        for s in sockets:
92            s = s()
93            if s and not s.closed:
94                if linger:
95                    s.setsockopt(LINGER, linger)
96                s.close()
97
98        self.term()
99
100__all__ = ['Context']
101