RemoteHandleControlBlock.h
Go to the documentation of this file.
1/*
2 * This file is part of ArmarX.
3 *
4 * Copyright (C) 2011-2016, High Performance Humanoid Technologies (H2T), Karlsruhe Institute of Technology (KIT), all rights reserved.
5 *
6 * ArmarX is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * ArmarX is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18* @package ArmarXCore
19* @author Raphael Grimm ( raphael dot grimm at kit dot edu)
20* @date 2016
21* @copyright http://www.gnu.org/licenses/gpl-2.0.txt
22* GNU General Public License
23*/
24#pragma once
25
26#include <atomic>
27#include <chrono>
28#include <condition_variable>
29#include <functional>
30#include <memory>
31#include <thread>
32
33#include <Ice/ObjectAdapter.h>
34#include <IceUtil/UUID.h>
35
36#include <ArmarXCore/interface/core/util/distributed/RemoteHandle/RemoteHandleControlBlock.h>
37
41
42namespace armarx
43{
46
47 /**
48 * @brief This holds the shared state of all RemoteHandleControlBlocks for one armarx manager.
49 * It holds a thread responsible for deleting them when their usecount reaches zero and the deletion delay has passed.
50 */
52 {
53 public:
54 /**
55 * @brief The amount of time (in ms) required to pass after a RemoteHandleControlBlock's usecount has reacht zero, before it is deleted.
56 */
57 static const unsigned int DEFAULT_DELETION_DELAY;
59
60 SharedRemoteHandleState(unsigned int deletionDelayMs);
62
64
65 private:
66 void sweep();
67
68 std::mutex stateMutex;
69
70 //must not invalidate other iterators on erase (ok for std::set)
71 std::set<RemoteHandleControlBlockPtr> rhs;
72 std::chrono::milliseconds deletionDelay;
74 };
75
76 /**
77 * @brief The RemoteHandleControlBlock is the equivalent of the std::shared_ptr's contol_block for a remote handle.
78 * It does reference counting and object deletion.
79 *
80 * This class is created on server side and a ClientSideRemoteHandleControlBlock is send to the client.
81 * Only create the class by calling RemoteHandleControlBlock::create.
82 *
83 * A direct pointer can be used to force the deletion of the managed object.
84 * The deletion has to be done by a passed deleter (it may hold the only pointer to the managed object or execute code to remove the object from some structure).
85 * The deleter should do any unregistering for the managed object (e.g. remove the object from from an ice object adapter)
86 *
87 * a object may leak if a connection error stops the message send when a handle is deleted (this stops the usecount from reaching zero).
88 * a object may be deleted with handles still alive if:
89 * 1) the object's deletion was forced
90 * 2) a scenario equivalent to this:
91 * pc A has the object and sends a handle to B
92 * pc B has now the only handle
93 * pc B now sends the handle to pc C and delets the handle before C deserialized the object (this could be done via a broadcast)
94 * The handle is deserialized after the deletion timeout set via property (default 3 sec) has passed.
95 * This scenario is possible but should not happen on a stable LAN if ice objects are not keept in a serialized form for a longer period.
96 *
97 * (for more info: \ref ArmarXCore-Tutorials-RemoteHandles "RemoteHandle tutorial")
98 *
99 * \ingroup Distributed
100 */
101 class RemoteHandleControlBlock : virtual public RemoteHandleControlBlockInterface
102 {
103 public:
104 using clock = std::chrono::steady_clock;
105 inline static int64_t now();
106
107 /**
108 * @brief Returned by a call to RemoteHandleControlBlock::create.
109 * It holds a direct handle to the controlblock (can be used to keep the RemoteHandleControlBlock alive (but not the managed object)) (this pointer may be deleted).
110 * And The ClientSideRemoteHandleControlBlock keeping the managed object alive. (send this to the client)
111 */
113 {
115 ClientSideRemoteHandleControlBlockBasePtr clientSideRemoteHandleControlBlock;
116 };
117
118 /**
119 * @brief Creates a new RemoteHandleControlBlock.
120 * @param objectAdapter The adapter used to register the RemoteHandleControlBlock to ice.
121 * @param managedObjectPrx A Proxy to the managed object.
122 * @param deleter A functor cleaning up the managed object. (has to delete it and unregister it)
123 * The Functor may have the only pointer keeping the managed object alive.
124 * @return A direct pointer to the created RemoteHandleControlBlock and the ClientSideRemoteHandleControlBlock keeping the managed object alive.
125 */
126 template <class Deleter>
127 static ManagementData
128 create(ArmarXManagerPtr manager, Ice::ObjectPrx managedObjectPrx, Deleter deleter);
129
130 /**
131 * @brief Increments the usecount.
132 * DO NOT CALL IT. (if you do, you are responsible to call decrementUseCount!)
133 */
134 inline void incrementUseCount(const Ice::Current& = Ice::emptyCurrent) override;
135 /**
136 * @brief decrements the useCount.
137 * DO NOT CALL IT. (except you have called incrementUseCount)
138 */
139 void decrementUseCount(const Ice::Current& = Ice::emptyCurrent) override;
140 /**
141 * @return Returns the current use count.
142 */
143 inline Ice::Long getUseCount(const Ice::Current& = Ice::emptyCurrent) const override;
144
145 /**
146 * @return A new ClientSideRemoteHandleControlBlock.
147 */
148 ClientSideRemoteHandleControlBlockBasePtr
149 getClientSideRemoteHandleControlBlock(const Ice::Current& = Ice::emptyCurrent) override;
150 inline Ice::ObjectPrx
151 getManagedObjectProxy(const Ice::Current& = Ice::emptyCurrent) const override;
152
153 /**
154 * @brief Call this when you want to force the deletion of the managed object.
155 * It will be deleted ignoring the usecount.
156 * This may be used to ensure the deletion of all objects created by yout server when shutting down.
157 * This may be necessary if a client's decrementUseCount was lost by the network.
158 */
159 void
161 {
162 forcedDeletion = true;
163 }
164
165 private:
167 Ice::ObjectPrx managedObjectPrx,
168 std::function<void(void)> deleter);
171
172 /**
173 * @brief Does all cleanup for this object.
174 */
175 inline void cleanup();
176
177 /**
178 * @brief The adapter used to register this RemoteHandleControlBlock
179 */
180 Ice::ObjectAdapterPtr objectAdapter;
181 std::function<void(void)> deleter;
182 Ice::ObjectPrx managedObjectProxy;
183 /**
184 * @brief A proxy to this RemoteHandleControlBlock (used when creating a new ClientSideRemoteHandleControlBlock)
185 */
186 RemoteHandleControlBlockInterfacePrx selfProxy;
187
188 mutable std::atomic<uint64_t> useCount{0};
189 mutable std::mutex mtx;
190 mutable clock::time_point lastTimeUseCountReachedZero;
191 mutable std::atomic_bool forcedDeletion{false};
192
194 };
195
196 void
198 {
199 ++useCount;
200 }
201
202 Ice::Long
203 RemoteHandleControlBlock::getUseCount(const Ice::Current&) const
204 {
205 return useCount;
206 }
207
208 Ice::ObjectPrx
210 {
211 return managedObjectProxy;
212 }
213
214 void
215 RemoteHandleControlBlock::cleanup()
216 {
217 //delete payload
218 deleter();
219 deleter = []() {
220 }; //do this to delete objects keept alive by the deleter (it may hold a unique_ptr)
221 //clean up proxy
222 objectAdapter->remove(selfProxy->ice_getIdentity());
223 }
224
225 template <class Deleter>
228 Ice::ObjectPrx managedObjectPrx,
229 Deleter deleter)
230 {
231 RemoteHandleControlBlockPtr block = new RemoteHandleControlBlock{
232 manager->getAdapter(), std::move(managedObjectPrx), std::move(deleter)};
233 auto clientSideRemoteHandleControlBlock = block->getClientSideRemoteHandleControlBlock();
234 manager->getSharedRemoteHandleState()->add(block);
235 return {block, clientSideRemoteHandleControlBlock};
236 }
237} // namespace armarx
The periodic task executes one thread method repeatedly using the time period specified in the constr...
IceUtil::Handle< PeriodicTask< SharedRemoteHandleState > > pointer_type
The RemoteHandleControlBlock is the equivalent of the std::shared_ptr's contol_block for a remote han...
void incrementUseCount(const Ice::Current &=Ice::emptyCurrent) override
Increments the usecount.
Ice::Long getUseCount(const Ice::Current &=Ice::emptyCurrent) const override
void decrementUseCount(const Ice::Current &=Ice::emptyCurrent) override
decrements the useCount.
ClientSideRemoteHandleControlBlockBasePtr getClientSideRemoteHandleControlBlock(const Ice::Current &=Ice::emptyCurrent) override
static ManagementData create(ArmarXManagerPtr manager, Ice::ObjectPrx managedObjectPrx, Deleter deleter)
Creates a new RemoteHandleControlBlock.
void forceDeletion()
Call this when you want to force the deletion of the managed object.
Ice::ObjectPrx getManagedObjectProxy(const Ice::Current &=Ice::emptyCurrent) const override
::IceInternal::Handle<::Ice::ObjectAdapter > ObjectAdapterPtr
Definition IceManager.h:52
This file offers overloads of toIce() and fromIce() functions for STL container types.
IceUtil::Handle< ArmarXManager > ArmarXManagerPtr
IceInternal::Handle< RemoteHandleControlBlock > RemoteHandleControlBlockPtr
Returned by a call to RemoteHandleControlBlock::create.
ClientSideRemoteHandleControlBlockBasePtr clientSideRemoteHandleControlBlock
void add(RemoteHandleControlBlockPtr rh)
SharedRemoteHandleState(unsigned int deletionDelayMs)
PeriodicTask< SharedRemoteHandleState > PeriodicTaskType
static const unsigned int DEFAULT_DELETION_DELAY
The amount of time (in ms) required to pass after a RemoteHandleControlBlock's usecount has reacht ze...