1 | /* |
2 | Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file |
3 | |
4 | This file is part of libzmq, the ZeroMQ core engine in C++. |
5 | |
6 | libzmq is free software; you can redistribute it and/or modify it under |
7 | the terms of the GNU Lesser General Public License (LGPL) as published |
8 | by the Free Software Foundation; either version 3 of the License, or |
9 | (at your option) any later version. |
10 | |
11 | As a special exception, the Contributors give you permission to link |
12 | this library with independent modules to produce an executable, |
13 | regardless of the license terms of these independent modules, and to |
14 | copy and distribute the resulting executable under terms of your choice, |
15 | provided that you also meet, for each linked independent module, the |
16 | terms and conditions of the license of that module. An independent |
17 | module is a module which is not derived from or based on this library. |
18 | If you modify this library, you must extend this exception to your |
19 | version of the library. |
20 | |
21 | libzmq is distributed in the hope that it will be useful, but WITHOUT |
22 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
23 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public |
24 | License for more details. |
25 | |
26 | You should have received a copy of the GNU Lesser General Public License |
27 | along with this program. If not, see <http://www.gnu.org/licenses/>. |
28 | */ |
29 | |
30 | #include "precompiled.hpp" |
31 | #include "decoder_allocators.hpp" |
32 | |
33 | #include "msg.hpp" |
34 | |
35 | zmq::shared_message_memory_allocator::shared_message_memory_allocator ( |
36 | std::size_t bufsize_) : |
37 | _buf (NULL), |
38 | _buf_size (0), |
39 | _max_size (bufsize_), |
40 | _msg_content (NULL), |
41 | _max_counters ((_max_size + msg_t::max_vsm_size - 1) / msg_t::max_vsm_size) |
42 | { |
43 | } |
44 | |
45 | zmq::shared_message_memory_allocator::shared_message_memory_allocator ( |
46 | std::size_t bufsize_, std::size_t max_messages_) : |
47 | _buf (NULL), |
48 | _buf_size (0), |
49 | _max_size (bufsize_), |
50 | _msg_content (NULL), |
51 | _max_counters (max_messages_) |
52 | { |
53 | } |
54 | |
55 | zmq::shared_message_memory_allocator::~shared_message_memory_allocator () |
56 | { |
57 | deallocate (); |
58 | } |
59 | |
60 | unsigned char *zmq::shared_message_memory_allocator::allocate () |
61 | { |
62 | if (_buf) { |
63 | // release reference count to couple lifetime to messages |
64 | zmq::atomic_counter_t *c = |
65 | reinterpret_cast<zmq::atomic_counter_t *> (_buf); |
66 | |
67 | // if refcnt drops to 0, there are no message using the buffer |
68 | // because either all messages have been closed or only vsm-messages |
69 | // were created |
70 | if (c->sub (1)) { |
71 | // buffer is still in use as message data. "Release" it and create a new one |
72 | // release pointer because we are going to create a new buffer |
73 | release (); |
74 | } |
75 | } |
76 | |
77 | // if buf != NULL it is not used by any message so we can re-use it for the next run |
78 | if (!_buf) { |
79 | // allocate memory for reference counters together with reception buffer |
80 | std::size_t const allocationsize = |
81 | _max_size + sizeof (zmq::atomic_counter_t) |
82 | + _max_counters * sizeof (zmq::msg_t::content_t); |
83 | |
84 | _buf = static_cast<unsigned char *> (std::malloc (allocationsize)); |
85 | alloc_assert (_buf); |
86 | |
87 | new (_buf) atomic_counter_t (1); |
88 | } else { |
89 | // release reference count to couple lifetime to messages |
90 | zmq::atomic_counter_t *c = |
91 | reinterpret_cast<zmq::atomic_counter_t *> (_buf); |
92 | c->set (1); |
93 | } |
94 | |
95 | _buf_size = _max_size; |
96 | _msg_content = reinterpret_cast<zmq::msg_t::content_t *> ( |
97 | _buf + sizeof (atomic_counter_t) + _max_size); |
98 | return _buf + sizeof (zmq::atomic_counter_t); |
99 | } |
100 | |
101 | void zmq::shared_message_memory_allocator::deallocate () |
102 | { |
103 | zmq::atomic_counter_t *c = reinterpret_cast<zmq::atomic_counter_t *> (_buf); |
104 | if (_buf && !c->sub (1)) { |
105 | std::free (_buf); |
106 | } |
107 | clear (); |
108 | } |
109 | |
110 | unsigned char *zmq::shared_message_memory_allocator::release () |
111 | { |
112 | unsigned char *b = _buf; |
113 | clear (); |
114 | return b; |
115 | } |
116 | |
117 | void zmq::shared_message_memory_allocator::clear () |
118 | { |
119 | _buf = NULL; |
120 | _buf_size = 0; |
121 | _msg_content = NULL; |
122 | } |
123 | |
124 | void zmq::shared_message_memory_allocator::inc_ref () |
125 | { |
126 | (reinterpret_cast<zmq::atomic_counter_t *> (_buf))->add (1); |
127 | } |
128 | |
129 | void zmq::shared_message_memory_allocator::call_dec_ref (void *, void *hint_) |
130 | { |
131 | zmq_assert (hint_); |
132 | unsigned char *buf = static_cast<unsigned char *> (hint_); |
133 | zmq::atomic_counter_t *c = reinterpret_cast<zmq::atomic_counter_t *> (buf); |
134 | |
135 | if (!c->sub (1)) { |
136 | c->~atomic_counter_t (); |
137 | std::free (buf); |
138 | buf = NULL; |
139 | } |
140 | } |
141 | |
142 | |
143 | std::size_t zmq::shared_message_memory_allocator::size () const |
144 | { |
145 | return _buf_size; |
146 | } |
147 | |
148 | unsigned char *zmq::shared_message_memory_allocator::data () |
149 | { |
150 | return _buf + sizeof (zmq::atomic_counter_t); |
151 | } |
152 | |