Instrument Neutral Distributed Interface INDI 2.2.5
SerializedMsg.cpp
Go to the documentation of this file.
1/* INDI Server for protocol version 1.7.
2 * Copyright (C) 2007 Elwood C. Downey <[email protected]>
3 2013 Jasem Mutlaq <[email protected]>
4 2022 Ludovic Pollet
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18*/
19#include "SerializedMsg.hpp"
20#include "Msg.hpp"
21#include "MsgChunck.hpp"
22#include "MsgChunckIterator.hpp"
23#include "MsgQueue.hpp"
24
25#include <thread>
26
27SerializedMsg::SerializedMsg(Msg * parent) : asyncProgress(), owner(parent), awaiters(), chuncks(), ownBuffers()
28{
29 blockedProducer = nullptr;
30 // At first, everything is required.
31 for(auto fd : parent->sharedBuffers)
32 {
33 if (fd != -1)
34 {
35 requirements.sharedBuffers.insert(fd);
36 }
37 }
38 requirements.xml = true;
40 asyncProgress.set<SerializedMsg, &SerializedMsg::async_progressed>(this);
41}
42
43// Delete occurs when no async task is running and no awaiters are left
45{
46 for(auto buff : ownBuffers)
47 {
48 free(buff);
49 }
50}
51
53{
54 std::lock_guard<std::recursive_mutex> guard(lock);
56}
57
59{
60 std::lock_guard<std::recursive_mutex> guard(lock);
61 if (this->requirements == req)
62 {
63 return;
64 }
65 this->requirements = req;
66 asyncProgress.send();
67}
68
70{
71 std::lock_guard<std::recursive_mutex> guard(lock);
72
73 this->chuncks.push_back(m);
74 asyncProgress.send();
75}
76
78{
79 std::lock_guard<std::recursive_mutex> guard(lock);
81 asyncProgress.send();
82}
83
84void SerializedMsg::async_start()
85{
86 std::lock_guard<std::recursive_mutex> guard(lock);
88 {
89 return;
90 }
91
94 {
95 asyncProgress.start();
96
97 std::thread t([this]()
98 {
100 });
101 t.detach();
102 }
103 else
104 {
106 }
107}
108
109void SerializedMsg::async_progressed()
110{
111 std::lock_guard<std::recursive_mutex> guard(lock);
112
114 {
115 // FIXME: unblock ?
116 asyncProgress.stop();
117 }
118
119 // Update ios of awaiters
120 for(auto awaiter : awaiters)
121 {
122 awaiter->messageMayHaveProgressed(this);
123 }
124
125 // Then prune
126 owner->prune();
127}
128
130{
131 std::lock_guard<std::recursive_mutex> guard(lock);
132
134}
135
136
138{
139 std::lock_guard<std::recursive_mutex> guard(lock);
140
142 {
143 async_start();
144 }
145
147 {
148 return true;
149 }
150
151 // Not reached the last chunck
152 if (position.chunckId < chuncks.size())
153 {
154 return true;
155 }
156
157 return false;
158}
159
160bool SerializedMsg::getContent(MsgChunckIterator &from, void* &data, ssize_t &size,
161 std::vector<int, std::allocator<int> > &sharedBuffers)
162{
163 std::lock_guard<std::recursive_mutex> guard(lock);
164
165 if (asyncStatus != SerializationStatus::terminated && from.chunckId >= chuncks.size())
166 {
167 // Not ready yet
168 return false;
169 }
170
171 if (from.chunckId == chuncks.size())
172 {
173 // Done
174 data = 0;
175 size = 0;
176 from.endReached = true;
177 return true;
178 }
179
180 const MsgChunck &ck = chuncks[from.chunckId];
181
182 if (from.chunckOffset == 0)
183 {
184 sharedBuffers = ck.sharedBufferIdsToAttach;
185 }
186 else
187 {
188 sharedBuffers.clear();
189 }
190
191 data = ck.content + from.chunckOffset;
192 size = ck.contentLength - from.chunckOffset;
193 return true;
194}
195
197{
198 std::lock_guard<std::recursive_mutex> guard(lock);
199
200 MsgChunck &cur = chuncks[iter.chunckId];
201 iter.chunckOffset += s;
202 if (iter.chunckOffset >= cur.contentLength)
203 {
204 iter.chunckId ++ ;
205 iter.chunckOffset = 0;
206 if (iter.chunckId >= chuncks.size() && asyncStatus == SerializationStatus::terminated)
207 {
208 iter.endReached = true;
209 }
210 }
211}
212
214{
215 awaiters.insert(q);
216}
217
219{
220 awaiters.erase(q);
221 if (awaiters.empty() && !isAsyncRunning())
222 {
223 owner->releaseSerialization(this);
224 }
225}
226
228{
229 sr.add(requirements);
230}
231
232// This is called when a received message require additional // work, to avoid overflow
234{
235 // TODO : implement or remove
236 (void) receiver;
237}
238
240{
241 return owner->queueSize;
242}
Definition Msg.hpp:33
void async_updateRequirement(const SerializationRequirement &n)
SerializationStatus asyncStatus
bool getContent(MsgChunckIterator &position, void *&data, ssize_t &nsend, std::vector< int > &sharedBuffers)
virtual bool generateContentAsync() const =0
MsgQueue * blockedProducer
void collectRequirements(SerializationRequirement &req)
std::list< void * > ownBuffers
void blockReceiver(MsgQueue *toblock)
virtual ~SerializedMsg()
ssize_t queueSize()
bool requestContent(const MsgChunckIterator &position)
std::set< MsgQueue * > awaiters
virtual void generateContent()=0
SerializedMsg(Msg *parent)
void advance(MsgChunckIterator &position, ssize_t s)
void addAwaiter(MsgQueue *awaiter)
void release(MsgQueue *from)
void async_pushChunck(const MsgChunck &m)
int fd
std::unique_ptr< RadioSim > receiver(new RadioSim())