1
/*
2
* \brief Utilities for object life-time management
3
* \author Norman Feske
4
* \date 2013-03-09
5
*/
6
7
/*
8
* Copyright (C) 2013 Genode Labs GmbH
9
*
10
* This file is part of the Genode OS framework, which is distributed
11
* under the terms of the GNU General Public License version 2.
12
*/
13
14
#
ifndef _INCLUDE__BASE__WEAK_PTR_H_
15
#
define _INCLUDE__BASE__WEAK_PTR_H_
16
17
#
include <base/lock.h>
18
#
include <base/printf.h>
19
#
include <util/list.h>
20
21
namespace
Genode {
22
class
Weak_object_base;
23
class
Weak_ptr_base;
24
class
Locked_ptr_base;
25
26
template
<
typename
T
>
struct
Weak_object;
27
template
<
typename
T
>
struct
Weak_ptr;
28
template
<
typename
T
>
struct
Locked_ptr;
29
}
30
31
32
/**
33
* Type-agnostic base class of a weak pointer
34
*
35
* This class implements the mechanics of the the `Weak_ptr` class template.
36
* It is not used directly.
37
*/
38
class
Genode::
Weak_ptr_base :
public
Genode::
List<
Weak_ptr_base
>
::
Element
39
{
40
private
:
41
42
friend
class
Weak_object_base;
43
friend
class
Locked_ptr_base;
44
45
Lock mutable _lock;
46
Weak_object_base *
_obj;
47
48
/*
49
* This lock is used to synchronize destruction of a weak pointer
50
* and its corresponding weak object that happen simultanously
51
*/
52
Lock mutable _destruct_lock {
Lock::
LOCKED }
;
53
54
inline
void
_adopt(
Weak_object_base *
obj
)
;
55
inline
void
_disassociate(
)
;
56
57
protected
:
58
59
explicit
inline
Weak_ptr_base(
Weak_object_base *
obj
)
;
60
61
public
:
62
63
/**
64
* Default constructor, produces invalid pointer
65
*/
66
inline
Weak_ptr_base(
)
;
67
68
inline
~
Weak_ptr_base(
)
;
69
70
/**
71
* Assignment operator
72
*/
73
inline
void
operator
=
(
Weak_ptr_base const
&
other
)
;
74
75
/**
76
* Test for equality
77
*/
78
inline
bool
operator
==
(
Weak_ptr_base const
&
other
)
const
;
79
80
/**
81
* Return pointer to object if it exists, or 0 if object vanished
82
*
83
* \noapi
84
*/
85
Weak_object_base *
obj(
)
const
{
return
_obj
;
}
86
87
/**
88
* Inspection hook for unit test
89
*
90
* \noapi
91
*/
92
void
debug_info(
)
const
;
93
}
;
94
95
96
/**
97
* Type-agnostic base class of a weak object
98
*/
99
class
Genode::
Weak_object_base
100
{
101
private
:
102
103
friend
class
Weak_ptr_base;
104
friend
class
Locked_ptr_base;
105
106
/**
107
* List of weak pointers currently pointing to the object
108
*/
109
Lock _list_lock;
110
List<
Weak_ptr_base
>
_list;
111
112
/**
113
* Buffers dequeued weak pointer that get invalidated currently
114
*/
115
Weak_ptr_base *
_ptr_in_destruction =
nullptr;
116
117
/**
118
* Lock to synchronize access to object
119
*/
120
Lock _lock;
121
122
protected
:
123
124
/**
125
* To be called from `Weak_object<T>` only
126
*
127
* \noapi
128
*/
129
template
<
typename
T
>
130
Weak_ptr<
T
>
_weak_ptr(
)
;
131
132
public
:
133
134
/**
135
* This exception signals a weak pointer that the object
136
* is in destruction progress
137
*/
138
class
In_destruction :
Exception
{
}
;
139
140
~
Weak_object_base(
)
141
{
142
if
(
_list.
first(
)
)
143
PERR(
"Weak object %p not destructed properly "
144
"there are still dangling pointers to it"
,
this)
;
145
}
146
147
void
disassociate(
Weak_ptr_base *
ptr
)
148
{
149
if
(
!
ptr)
return
;
150
151
{
152
Lock::
Guard
guard(
_list_lock
)
;
153
154
/*
155
* If the weak pointer that tries to disassociate is currently
156
* removed to invalidate it by the weak object`s destructor,
157
* signal that fact to the pointer, so it can free it`s lock,
158
* and block until invalidation is finished.
159
*/
160
if
(
_ptr_in_destruction ==
ptr)
161
throw
In_destruction(
)
;
162
163
_list.
remove(
ptr)
;
164
}
165
}
166
167
/**
168
* Mark object as safe to be destructed
169
*
170
* This method must be called by the destructor of a weak object to
171
* defer the destruction until no `Locked_ptr` is held to the object.
172
*/
173
void
lock_for_destruction(
)
174
{
175
/*
176
* Loop through the list of weak pointers and invalidate them
177
*/
178
while
(
true)
{
179
180
/*
181
* To prevent dead-locks we always have to hold
182
* the order of lock access, therefore we first
183
* dequeue one weak pointer and free the list lock again
184
*/
185
{
186
Lock::
Guard
guard(
_list_lock
)
;
187
_ptr_in_destruction =
_list.
first(
)
;
188
189
/* if the list is empty we`re done */
190
if
(
!
_ptr_in_destruction)
break;
191
_list.
remove(
_ptr_in_destruction)
;
192
}
193
194
{
195
Lock::
Guard
guard(
_ptr_in_destruction->
_lock
)
;
196
_ptr_in_destruction->
_obj =
nullptr;
197
198
/*
199
* unblock a weak pointer that tried to disassociate
200
* in the meantime
201
*/
202
_ptr_in_destruction->
_destruct_lock.
unlock(
)
;
203
}
204
}
205
206
/*
207
* synchronize with locked pointers that already aquired
208
* the lock before the corresponding weak pointer got invalidated
209
*/
210
_lock.
lock(
)
;
211
}
212
213
/**
214
* Inspection hook for unit test
215
*
216
* \noapi
217
*/
218
void
debug_info(
)
const
;
219
}
;
220
221
222
class
Genode::
Locked_ptr_base
223
{
224
protected
:
225
226
Weak_object_base *
curr;
227
228
/**
229
* Constructor
230
*
231
* \noapi
232
*/
233
inline
Locked_ptr_base(
Weak_ptr_base &
weak_ptr
)
;
234
235
/**
236
* Destructor
237
*
238
* \noapi
239
*/
240
inline
~
Locked_ptr_base(
)
;
241
}
;
242
243
244
/**
245
* Weak pointer to a given type
246
*
247
* A weak pointer can be obtained from a weak object (an object that inherits
248
* the `Weak_object` class template) and safely survives the lifetime of the
249
* associated weak object. If the weak object disappears, all
250
* weak pointers referring to the object are automatically invalidated.
251
* To avoid race conditions between the destruction and use of a weak object,
252
* a weak pointer cannot be de-reference directly. To access the object, a
253
* weak pointer must be turned into a locked pointer (`Locked_ptr`).
254
*/
255
template
<
typename
T
>
256
struct
Genode::
Weak_ptr :
Genode::
Weak_ptr_base
257
{
258
/**
259
* Default constructor creates invalid pointer
260
*/
261
Weak_ptr(
)
{
}
262
263
/**
264
* Copy constructor
265
*/
266
Weak_ptr(
Weak_ptr<
T
>
const
&
other
)
:
Weak_ptr_base(
other.
obj(
)
)
{
}
267
268
/**
269
* Assignment operator
270
*/
271
inline
void
operator
=
(
Weak_ptr<
T
>
const
&
other
)
272
{
273
*
static_cast
<
Weak_ptr_base *
>
(
this)
=
other;
274
}
275
}
;
276
277
278
/**
279
* Weak object
280
*
281
* This class template must be inherited in order to equip an object with
282
* the weak-pointer mechanism.
283
*
284
* \param T type of the derived class
285
*/
286
template
<
typename
T
>
287
struct
Genode::
Weak_object :
Genode::
Weak_object_base
288
{
289
/**
290
* Obtain a weak pointer referring to the weak object
291
*/
292
Weak_ptr<
T
>
weak_ptr(
)
{
return
_weak_ptr<
T
>
(
)
;
}
293
294
/**
295
* Const version of `weak_ptr`
296
*
297
* This function is useful in cases where the returned weak pointer is
298
* merely used for comparison operations.
299
*/
300
Weak_ptr<
T const
>
const
weak_ptr_const(
)
const
301
{
302
/*
303
* We strip off the constness of `this` to reuse the internal non-const
304
* code of the weak object. The executed operations are known to not
305
* alter the state of the weak object.
306
*/
307
return
const_cast<
Weak_object *
>
(
this)
->
_weak_ptr<
T const
>
(
)
;
308
}
309
}
;
310
311
312
/**
313
* Locked pointer
314
*
315
* A locked pointer is constructed from a weak pointer. After construction,
316
* its validity can (and should) be checked by calling the `is_valid`
317
* method. If the locked pointer is valid, the pointed-to object is known to
318
* be locked until the locked pointer is destroyed. During this time, the
319
* locked pointer can safely be de-referenced.
320
*
321
* The typical pattern of using a locked pointer is to declare it as a
322
* local variable. Once the execution leaves the scope of the variable, the
323
* locked pointer is destructed, which unlocks the pointed-to weak object.
324
* It effectively serves as a lock guard.
325
*/
326
template
<
typename
T
>
327
struct
Genode::
Locked_ptr :
Genode::
Locked_ptr_base
328
{
329
Locked_ptr(
Weak_ptr<
T
>
&
weak_ptr
)
:
Locked_ptr_base(
weak_ptr)
{
}
330
331
T *
operator
->
(
)
{
return
static_cast
<
T *
>
(
curr)
;
}
332
333
T &
operator
*
(
)
{
return
*
static_cast
<
T *
>
(
curr)
;
}
334
335
/**
336
* Returns true if the locked pointer is valid
337
*
338
* Only if valid, the locked pointer can be de-referenced. Otherwise,
339
* the attempt will result in a null-pointer access.
340
*/
341
bool
is_valid(
)
const
{
return
curr !=
nullptr
;
}
342
}
;
343
344
345
/********************
346
** Implementation **
347
********************/
348
349
void
Genode::
Weak_ptr_base::
_adopt(
Genode::
Weak_object_base *
obj
)
350
{
351
if
(
!
obj)
352
return
;
353
354
_obj =
obj;
355
356
{
357
Lock::
Guard
guard(
_obj->
_list_lock
)
;
358
_obj->
_list.
insert(
this)
;
359
}
360
}
361
362
363
void
Genode::
Weak_ptr_base::
_disassociate(
)
364
{
365
/* defer destruction of object */
366
try
{
367
Lock::
Guard
guard(
_lock
)
;
368
369
if
(
_obj)
_obj->
disassociate(
this)
;
370
}
catch
(
Weak_object_base::
In_destruction&
)
{
371
_destruct_lock.
lock(
)
;
372
}
373
}
374
375
376
Genode::
Weak_ptr_base::
Weak_ptr_base(
Genode::
Weak_object_base *
obj
)
377
{
378
_adopt(
obj)
;
379
}
380
381
382
Genode::
Weak_ptr_base::
Weak_ptr_base(
)
:
_obj(
nullptr)
{
}
383
384
385
void Genode::
Weak_ptr_base::
operator
=
(
Weak_ptr_base const
&
other
)
386
{
387
/* self assignment */
388
if
(
&
other ==
this)
389
return
;
390
391
_disassociate(
)
;
392
{
393
Lock::
Guard
guard(
other.
_lock
)
;
394
_adopt(
other.
_obj)
;
395
}
396
}
397
398
399
bool Genode::
Weak_ptr_base::
operator
==
(
Weak_ptr_base const
&
other
)
const
400
{
401
if
(
&
other ==
this)
402
return
true
;
403
404
Lock::
Guard guard_this(
_lock)
,
guard_other(
other.
_lock)
;
405
406
return
(
_obj ==
other.
_obj)
;
407
}
408
409
410
Genode::
Weak_ptr_base::
~
Weak_ptr_base(
)
411
{
412
_disassociate(
)
;
413
}
414
415
416
template
<
typename
T
>
417
Genode::
Weak_ptr<
T
>
Genode::
Weak_object_base::
_weak_ptr(
)
418
{
419
Weak_ptr_base
result(
this
)
;
420
return
*
static_cast
<
Weak_ptr<
T
>
*
>
(
&
result)
;
421
}
422
423
424
Genode::
Locked_ptr_base::
Locked_ptr_base(
Weak_ptr_base &
weak_ptr
)
425
:
curr(
nullptr)
426
{
427
Lock::
Guard
guard(
weak_ptr.
_lock
)
;
428
429
if
(
!
weak_ptr.
obj(
)
)
return
;
430
431
curr =
weak_ptr.
obj(
)
;
432
curr->
_lock.
lock(
)
;
433
}
434
435
436
Genode::
Locked_ptr_base::
~
Locked_ptr_base(
)
437
{
438
if
(
curr)
439
curr->
_lock.
unlock(
)
;
440
}
441
442
#
endif /* _INCLUDE__BASE__WEAK_PTR_H_ */