Skip to content

Commit e3511d1

Browse files
committed
Allow more children per entity
Sometimes application overflow the children counters in the handle flags. That leads to a bad crash, which is a bug, but it is also less than ideal than one can't make a great many child entities. With the way the bits are mapped, one can have 16k children of a single entity and 4k concurrent calls on a single entity. This commit changes that in two ways: * On 32-bit platforms, it shifts the division of bits, allowing up to 64k children and up to 1k concurrent calls on a single entity. It is clearly still possible to run into the same bug, and even slightly more likely to do so in progress with very many threads, but this seems like a minor improvement nonetheless. * On 64-bit platforms, it changes the representation to an 64-bit integer (it simply uses an uintptr_t), which gives plenty of room in the field to substantially increase the width of the counters. Just widening the counters is not an elegant solution, and 64-bits here is a bit wasteful. Still, this should fix the problem at least in practice. Signed-off-by: Erik Boasson <[email protected]>
1 parent cec4361 commit e3511d1

File tree

3 files changed

+66
-40
lines changed

3 files changed

+66
-40
lines changed

src/core/ddsc/src/dds__handles.h

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "dds/ddsrt/time.h"
1515
#include "dds/ddsrt/retcode.h"
1616
#include "dds/ddsrt/atomics.h"
17+
#include "dds/ddsrt/arch.h"
1718
#include "dds/dds.h"
1819

1920
#if defined (__cplusplus)
@@ -63,16 +64,29 @@ typedef int32_t dds_handle_t;
6364

6465
/* Closing & closed can be combined, but having two gives a means for enforcing
6566
that close() be called first, then close_wait(), and then delete(). */
67+
#if DDSRT_64BIT // Set for WIN64, _LP64 => sizeof(void*)=8 => uintptr_t=8 is a reasonable assumption
68+
69+
#define HDL_FLAG_CLOSING UINT64_C(0x8000000000000000)
70+
#define HDL_FLAG_DELETE_DEFERRED UINT64_C(0x4000000000000000)
71+
#define HDL_FLAG_PENDING UINT64_C(0x2000000000000000)
72+
#define HDL_FLAG_IMPLICIT UINT64_C(0x1000000000000000)
73+
#define HDL_FLAG_ALLOW_CHILDREN UINT64_C(0x0800000000000000) /* refc counts children */
74+
#define HDL_FLAG_NO_USER_ACCESS UINT64_C(0x0400000000000000)
75+
76+
#else
77+
6678
#define HDL_FLAG_CLOSING (0x80000000u)
6779
#define HDL_FLAG_DELETE_DEFERRED (0x40000000u)
6880
#define HDL_FLAG_PENDING (0x20000000u)
6981
#define HDL_FLAG_IMPLICIT (0x10000000u)
7082
#define HDL_FLAG_ALLOW_CHILDREN (0x08000000u) /* refc counts children */
7183
#define HDL_FLAG_NO_USER_ACCESS (0x04000000u)
7284

85+
#endif
86+
7387
struct dds_handle_link {
7488
dds_handle_t hdl;
75-
ddsrt_atomic_uint32_t cnt_flags;
89+
ddsrt_atomic_uintptr_t cnt_flags;
7690
};
7791

7892
/**
@@ -206,7 +220,7 @@ bool dds_handle_unpin_and_drop_ref (struct dds_handle_link *link);
206220
* possible.
207221
*/
208222
inline bool dds_handle_is_closed (struct dds_handle_link *link) {
209-
return (ddsrt_atomic_ld32 (&link->cnt_flags) & HDL_FLAG_CLOSING) != 0;
223+
return (ddsrt_atomic_ldptr (&link->cnt_flags) & HDL_FLAG_CLOSING) != 0;
210224
}
211225

212226
/** @component handles */

src/core/ddsc/src/dds_entity.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ void dds_entity_init_complete (dds_entity *entity)
307307
void dds_entity_register_child (dds_entity *parent, dds_entity *child)
308308
{
309309
/* parent must be tracking children in its refc, or children can't be added */
310-
assert (ddsrt_atomic_ld32 (&parent->m_hdllink.cnt_flags) & HDL_FLAG_ALLOW_CHILDREN);
310+
assert (ddsrt_atomic_ldptr (&parent->m_hdllink.cnt_flags) & HDL_FLAG_ALLOW_CHILDREN);
311311
assert (child->m_iid != 0);
312312
assert (ddsrt_avl_lookup (&dds_entity_children_td, &parent->m_children, &child->m_iid) == NULL);
313313
ddsrt_avl_insert (&dds_entity_children_td, &parent->m_children, child);

src/core/ddsc/src/dds_handles.c

Lines changed: 49 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,21 @@
1919
#include "dds__handles.h"
2020
#include "dds__types.h"
2121

22-
#define HDL_REFCOUNT_MASK (0x03fff000u)
23-
#define HDL_REFCOUNT_UNIT (0x00001000u)
24-
#define HDL_REFCOUNT_SHIFT 12
25-
#define HDL_PINCOUNT_MASK (0x00000fffu)
22+
#if DDSRT_64BIT // see dds__handles.h for reasoning
23+
24+
#define HDL_REFCOUNT_MASK UINT64_C(0x0003ffffff000000)
25+
#define HDL_REFCOUNT_UNIT UINT64_C(0x0000000001000000)
26+
#define HDL_REFCOUNT_SHIFT 24
27+
#define HDL_PINCOUNT_MASK UINT64_C(0x0000000000ffffff)
28+
29+
#else
30+
31+
#define HDL_REFCOUNT_MASK (0x03fffc00u)
32+
#define HDL_REFCOUNT_UNIT (0x00000400u)
33+
#define HDL_REFCOUNT_SHIFT 10
34+
#define HDL_PINCOUNT_MASK (0x000003ffu)
35+
36+
#endif
2637

2738
/*
2839
"regular" entities other than topics:
@@ -101,9 +112,10 @@ void dds_handle_server_fini (void)
101112
struct ddsrt_hh_iter it;
102113
for (struct dds_handle_link *link = ddsrt_hh_iter_first (handles.ht, &it); link != NULL; link = ddsrt_hh_iter_next (&it))
103114
{
104-
uint32_t cf = ddsrt_atomic_ld32 (&link->cnt_flags);
105-
DDS_ERROR ("handle %"PRId32" pin %"PRIu32" refc %"PRIu32"%s%s%s\n", link->hdl,
106-
cf & HDL_PINCOUNT_MASK, (cf & HDL_REFCOUNT_MASK) >> HDL_REFCOUNT_SHIFT,
115+
uintptr_t cf = ddsrt_atomic_ldptr (&link->cnt_flags);
116+
DDS_ERROR ("handle %"PRId32" pin %"PRIuPTR" refc %"PRIuPTR"%s%s%s\n", link->hdl,
117+
(uintptr_t) (cf & HDL_PINCOUNT_MASK),
118+
(uintptr_t) ((cf & HDL_REFCOUNT_MASK) >> HDL_REFCOUNT_SHIFT),
107119
cf & HDL_FLAG_PENDING ? " pending" : "",
108120
cf & HDL_FLAG_CLOSING ? " closing" : "",
109121
cf & HDL_FLAG_DELETE_DEFERRED ? " delete-deferred" : "");
@@ -119,11 +131,11 @@ void dds_handle_server_fini (void)
119131

120132
static dds_handle_t dds_handle_create_int (struct dds_handle_link *link, bool implicit, bool refc_counts_children, bool user_access)
121133
{
122-
uint32_t flags = HDL_FLAG_PENDING;
134+
uintptr_t flags = HDL_FLAG_PENDING;
123135
flags |= implicit ? HDL_FLAG_IMPLICIT : HDL_REFCOUNT_UNIT;
124136
flags |= refc_counts_children ? HDL_FLAG_ALLOW_CHILDREN : 0;
125137
flags |= user_access ? 0 : HDL_FLAG_NO_USER_ACCESS;
126-
ddsrt_atomic_st32 (&link->cnt_flags, flags | 1u);
138+
ddsrt_atomic_stptr (&link->cnt_flags, flags | 1u);
127139
do {
128140
do {
129141
link->hdl = (int32_t) (ddsrt_random () & INT32_MAX);
@@ -165,7 +177,7 @@ dds_return_t dds_handle_register_special (struct dds_handle_link *link, bool imp
165177
else
166178
{
167179
handles.count++;
168-
ddsrt_atomic_st32 (&link->cnt_flags, HDL_FLAG_PENDING | (implicit ? HDL_FLAG_IMPLICIT : HDL_REFCOUNT_UNIT) | (allow_children ? HDL_FLAG_ALLOW_CHILDREN : 0) | 1u);
180+
ddsrt_atomic_stptr (&link->cnt_flags, HDL_FLAG_PENDING | (implicit ? HDL_FLAG_IMPLICIT : HDL_REFCOUNT_UNIT) | (allow_children ? HDL_FLAG_ALLOW_CHILDREN : 0) | 1u);
169181
link->hdl = handle;
170182
if (ddsrt_hh_add (handles.ht, link))
171183
ret = handle;
@@ -180,21 +192,21 @@ dds_return_t dds_handle_register_special (struct dds_handle_link *link, bool imp
180192
void dds_handle_unpend (struct dds_handle_link *link)
181193
{
182194
#ifndef NDEBUG
183-
uint32_t cf = ddsrt_atomic_ld32 (&link->cnt_flags);
195+
uintptr_t cf = ddsrt_atomic_ldptr (&link->cnt_flags);
184196
assert ((cf & HDL_FLAG_PENDING));
185197
assert (!(cf & HDL_FLAG_DELETE_DEFERRED));
186198
assert (!(cf & HDL_FLAG_CLOSING));
187199
assert ((cf & HDL_REFCOUNT_MASK) >= HDL_REFCOUNT_UNIT || (cf & HDL_FLAG_IMPLICIT));
188200
assert ((cf & HDL_PINCOUNT_MASK) >= 1u);
189201
#endif
190-
ddsrt_atomic_and32 (&link->cnt_flags, ~HDL_FLAG_PENDING);
202+
ddsrt_atomic_andptr (&link->cnt_flags, ~HDL_FLAG_PENDING);
191203
dds_handle_unpin (link);
192204
}
193205

194206
int32_t dds_handle_delete (struct dds_handle_link *link)
195207
{
196208
#ifndef NDEBUG
197-
uint32_t cf = ddsrt_atomic_ld32 (&link->cnt_flags);
209+
uintptr_t cf = ddsrt_atomic_ldptr (&link->cnt_flags);
198210
if (!(cf & HDL_FLAG_PENDING))
199211
{
200212
assert (cf & HDL_FLAG_CLOSING);
@@ -210,7 +222,7 @@ int32_t dds_handle_delete (struct dds_handle_link *link)
210222
return DDS_RETCODE_OK;
211223
}
212224

213-
static int32_t dds_handle_pin_int (dds_handle_t hdl, uint32_t delta, bool from_user, struct dds_handle_link **link)
225+
static int32_t dds_handle_pin_int (dds_handle_t hdl, uintptr_t delta, bool from_user, struct dds_handle_link **link)
214226
{
215227
struct dds_handle_link dummy = { .hdl = hdl };
216228
int32_t rc;
@@ -231,12 +243,12 @@ static int32_t dds_handle_pin_int (dds_handle_t hdl, uint32_t delta, bool from_u
231243
rc = DDS_RETCODE_BAD_PARAMETER;
232244
else
233245
{
234-
uint32_t cf;
246+
uintptr_t cf;
235247
/* Assume success; bail out if the object turns out to be in the process of
236248
being deleted */
237249
rc = DDS_RETCODE_OK;
238250
do {
239-
cf = ddsrt_atomic_ld32 (&(*link)->cnt_flags);
251+
cf = ddsrt_atomic_ldptr (&(*link)->cnt_flags);
240252
if (cf & (HDL_FLAG_CLOSING | HDL_FLAG_PENDING | HDL_FLAG_NO_USER_ACCESS))
241253
{
242254
if (cf & (HDL_FLAG_CLOSING | HDL_FLAG_PENDING))
@@ -250,7 +262,7 @@ static int32_t dds_handle_pin_int (dds_handle_t hdl, uint32_t delta, bool from_u
250262
break;
251263
}
252264
}
253-
} while (!ddsrt_atomic_cas32 (&(*link)->cnt_flags, cf, cf + delta));
265+
} while (!ddsrt_atomic_casptr (&(*link)->cnt_flags, cf, cf + delta));
254266
}
255267
ddsrt_mutex_unlock (&handles.lock);
256268
return rc;
@@ -287,11 +299,11 @@ int32_t dds_handle_pin_for_delete (dds_handle_t hdl, bool explicit, bool from_us
287299
rc = DDS_RETCODE_BAD_PARAMETER;
288300
else
289301
{
290-
uint32_t cf, cf1;
302+
uintptr_t cf, cf1;
291303
/* Assume success; bail out if the object turns out to be in the process of
292304
being deleted */
293305
do {
294-
cf = ddsrt_atomic_ld32 (&(*link)->cnt_flags);
306+
cf = ddsrt_atomic_ldptr (&(*link)->cnt_flags);
295307

296308
if (from_user && (cf & (HDL_FLAG_NO_USER_ACCESS)))
297309
{
@@ -384,7 +396,7 @@ int32_t dds_handle_pin_for_delete (dds_handle_t hdl, bool explicit, bool from_us
384396
}
385397

386398
rc = ((cf1 & HDL_REFCOUNT_MASK) == 0 || (cf1 & HDL_FLAG_ALLOW_CHILDREN)) ? DDS_RETCODE_OK : DDS_RETCODE_TRY_AGAIN;
387-
} while (!ddsrt_atomic_cas32 (&(*link)->cnt_flags, cf, cf1));
399+
} while (!ddsrt_atomic_casptr (&(*link)->cnt_flags, cf, cf1));
388400
}
389401
ddsrt_mutex_unlock (&handles.lock);
390402
return rc;
@@ -394,9 +406,9 @@ bool dds_handle_drop_childref_and_pin (struct dds_handle_link *link, bool may_de
394406
{
395407
bool del_parent = false;
396408
ddsrt_mutex_lock (&handles.lock);
397-
uint32_t cf, cf1;
409+
uintptr_t cf, cf1;
398410
do {
399-
cf = ddsrt_atomic_ld32 (&link->cnt_flags);
411+
cf = ddsrt_atomic_ldptr (&link->cnt_flags);
400412

401413
if (cf & (HDL_FLAG_CLOSING | HDL_FLAG_PENDING))
402414
{
@@ -430,7 +442,7 @@ bool dds_handle_drop_childref_and_pin (struct dds_handle_link *link, bool may_de
430442
del_parent = false;
431443
}
432444
}
433-
} while (!ddsrt_atomic_cas32 (&link->cnt_flags, cf, cf1));
445+
} while (!ddsrt_atomic_casptr (&link->cnt_flags, cf, cf1));
434446
ddsrt_mutex_unlock (&handles.lock);
435447
return del_parent;
436448
}
@@ -442,21 +454,21 @@ int32_t dds_handle_pin_and_ref_with_origin (dds_handle_t hdl, bool from_user, st
442454

443455
void dds_handle_repin (struct dds_handle_link *link)
444456
{
445-
uint32_t x = ddsrt_atomic_inc32_nv (&link->cnt_flags);
457+
uintptr_t x = ddsrt_atomic_incptr_nv (&link->cnt_flags);
446458
(void) x;
447459
}
448460

449461
void dds_handle_unpin (struct dds_handle_link *link)
450462
{
451463
#ifndef NDEBUG
452-
uint32_t cf = ddsrt_atomic_ld32 (&link->cnt_flags);
464+
uintptr_t cf = ddsrt_atomic_ldptr (&link->cnt_flags);
453465
if (cf & HDL_FLAG_CLOSING)
454466
assert ((cf & HDL_PINCOUNT_MASK) > 1u);
455467
else
456468
assert ((cf & HDL_PINCOUNT_MASK) >= 1u);
457469
#endif
458470
ddsrt_mutex_lock (&handles.lock);
459-
if ((ddsrt_atomic_dec32_nv (&link->cnt_flags) & (HDL_FLAG_CLOSING | HDL_PINCOUNT_MASK)) == (HDL_FLAG_CLOSING | 1u))
471+
if ((ddsrt_atomic_decptr_nv (&link->cnt_flags) & (HDL_FLAG_CLOSING | HDL_PINCOUNT_MASK)) == (HDL_FLAG_CLOSING | 1u))
460472
{
461473
ddsrt_cond_broadcast (&handles.cond);
462474
}
@@ -465,17 +477,17 @@ void dds_handle_unpin (struct dds_handle_link *link)
465477

466478
void dds_handle_add_ref (struct dds_handle_link *link)
467479
{
468-
ddsrt_atomic_add32 (&link->cnt_flags, HDL_REFCOUNT_UNIT);
480+
ddsrt_atomic_addptr (&link->cnt_flags, HDL_REFCOUNT_UNIT);
469481
}
470482

471483
bool dds_handle_drop_ref (struct dds_handle_link *link)
472484
{
473-
uint32_t old, new;
485+
uintptr_t old, new;
474486
do {
475-
old = ddsrt_atomic_ld32 (&link->cnt_flags);
487+
old = ddsrt_atomic_ldptr (&link->cnt_flags);
476488
assert ((old & HDL_REFCOUNT_MASK) > 0);
477489
new = old - HDL_REFCOUNT_UNIT;
478-
} while (!ddsrt_atomic_cas32 (&link->cnt_flags, old, new));
490+
} while (!ddsrt_atomic_casptr (&link->cnt_flags, old, new));
479491
ddsrt_mutex_lock (&handles.lock);
480492
if ((new & (HDL_FLAG_CLOSING | HDL_PINCOUNT_MASK)) == (HDL_FLAG_CLOSING | 1u))
481493
{
@@ -487,13 +499,13 @@ bool dds_handle_drop_ref (struct dds_handle_link *link)
487499

488500
bool dds_handle_unpin_and_drop_ref (struct dds_handle_link *link)
489501
{
490-
uint32_t old, new;
502+
uintptr_t old, new;
491503
do {
492-
old = ddsrt_atomic_ld32 (&link->cnt_flags);
504+
old = ddsrt_atomic_ldptr (&link->cnt_flags);
493505
assert ((old & HDL_REFCOUNT_MASK) > 0);
494506
assert ((old & HDL_PINCOUNT_MASK) > 0);
495507
new = old - HDL_REFCOUNT_UNIT - 1u;
496-
} while (!ddsrt_atomic_cas32 (&link->cnt_flags, old, new));
508+
} while (!ddsrt_atomic_casptr (&link->cnt_flags, old, new));
497509
ddsrt_mutex_lock (&handles.lock);
498510
if ((new & (HDL_FLAG_CLOSING | HDL_PINCOUNT_MASK)) == (HDL_FLAG_CLOSING | 1u))
499511
{
@@ -505,27 +517,27 @@ bool dds_handle_unpin_and_drop_ref (struct dds_handle_link *link)
505517

506518
bool dds_handle_close (struct dds_handle_link *link)
507519
{
508-
uint32_t old = ddsrt_atomic_or32_ov (&link->cnt_flags, HDL_FLAG_CLOSING);
520+
uintptr_t old = ddsrt_atomic_orptr_ov (&link->cnt_flags, HDL_FLAG_CLOSING);
509521
return (old & HDL_REFCOUNT_MASK) == 0;
510522
}
511523

512524
void dds_handle_close_wait (struct dds_handle_link *link)
513525
{
514526
#ifndef NDEBUG
515-
uint32_t cf = ddsrt_atomic_ld32 (&link->cnt_flags);
527+
uintptr_t cf = ddsrt_atomic_ldptr (&link->cnt_flags);
516528
assert ((cf & HDL_FLAG_CLOSING));
517529
assert ((cf & HDL_PINCOUNT_MASK) >= 1u);
518530
#endif
519531
ddsrt_mutex_lock (&handles.lock);
520-
while ((ddsrt_atomic_ld32 (&link->cnt_flags) & HDL_PINCOUNT_MASK) != 1u)
532+
while ((ddsrt_atomic_ldptr (&link->cnt_flags) & HDL_PINCOUNT_MASK) != 1u)
521533
ddsrt_cond_wait (&handles.cond, &handles.lock);
522534
/* only one thread may call close_wait on a given handle */
523535
ddsrt_mutex_unlock (&handles.lock);
524536
}
525537

526538
bool dds_handle_is_not_refd (struct dds_handle_link *link)
527539
{
528-
return ((ddsrt_atomic_ld32 (&link->cnt_flags) & HDL_REFCOUNT_MASK) == 0);
540+
return ((ddsrt_atomic_ldptr (&link->cnt_flags) & HDL_REFCOUNT_MASK) == 0);
529541
}
530542

531543
extern inline bool dds_handle_is_closed (struct dds_handle_link *link);

0 commit comments

Comments
 (0)