
The old entity handle mechanism suffered from a number of problems, the most terrible one being that it would only ever allocate 1000 handles (not even have at most 1000 in use at the same time). Secondarily, it was protected by a single mutex that actually does show up as a limiting factor in, say, a polling-based throughput test with small messages. Thirdly, it tried to provide for various use cases that don't exist in practice but add complexity and overhead. This commit totally rewrites the mechanism, by replacing the old array with a hash table and allowing a near-arbitrary number of handles as well as reuse of handles. It also removes the entity "kind" bits in the most significant bits of the handles, because they only resulted in incorrect checking of argument validity. All that is taken out, but there is still more cleaning up to be done. It furthermore removes an indirection in the handle-to-entity lookup by embedding the "dds_handle_link" structure in the entity. Handle allocation is randomized to avoid the have a high probability of quickly finding an available handle (the total number of handles is limited to a number much smaller than the domain from which they are allocated). The likelihood of handle reuse is still dependent on the number of allocated handles -- the fewer handles there are, the longer the expected time to reuse. Non-randomized handles would give a few guarantees more, though. It moreover moves the code from the "util" to the "core/ddsc" component, because it really is only used for entities, and besides the new implementation relies on the deferred freeing (a.k.a. garbage collection mechanism) implemented in the core. The actual handle management has two variants, selectable with a macro: the preferred embodiment uses a concurrent hash table, the actually used one performs all operations inside a single mutex and uses a non-concurrent version of the hash table. The reason the less-predeferred embodiment is used is that the concurrent version requires the freeing of entity objects to be deferred (much like the GUID-to-entity hash tables in DDSI function, or indeed the key value to instance handle mapping). That is a fair bit of work, and the non-concurrent version is a reasonable intermediate step. Signed-off-by: Erik Boasson <eb@ilities.com>
158 lines
4.7 KiB
C
158 lines
4.7 KiB
C
/*
|
|
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
|
|
*
|
|
* This program and the accompanying materials are made available under the
|
|
* terms of the Eclipse Public License v. 2.0 which is available at
|
|
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
|
|
* v. 1.0 which is available at
|
|
* http://www.eclipse.org/org/documents/edl-v10.php.
|
|
*
|
|
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
|
|
*/
|
|
#include <stdio.h>
|
|
#include "CUnit/Test.h"
|
|
|
|
#include "dds/dds.h"
|
|
#include "RoundTrip.h"
|
|
|
|
#include "test-common.h"
|
|
|
|
static dds_entity_t e[8];
|
|
|
|
#define PAR (0) /* Participant */
|
|
#define TOP (1) /* Topic */
|
|
#define PUB (2) /* Publisher */
|
|
#define WRI (3) /* Writer */
|
|
#define SUB (4) /* Subscriber */
|
|
#define REA (5) /* Reader */
|
|
#define RCD (6) /* ReadCondition */
|
|
#define BAD (7) /* Bad (non-entity) */
|
|
|
|
struct index_result {
|
|
unsigned index;
|
|
dds_return_t exp_res;
|
|
};
|
|
|
|
static void
|
|
setup(void)
|
|
{
|
|
e[PAR] = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL);
|
|
CU_ASSERT_FATAL(e[PAR] > 0);
|
|
e[TOP] = dds_create_topic(e[PAR], &RoundTripModule_DataType_desc, "RoundTrip", NULL, NULL);
|
|
CU_ASSERT_FATAL(e[TOP] > 0);
|
|
e[PUB] = dds_create_publisher(e[PAR], NULL, NULL);
|
|
CU_ASSERT_FATAL(e[PUB] > 0);
|
|
e[WRI] = dds_create_writer(e[PUB], e[TOP], NULL, NULL);
|
|
CU_ASSERT_FATAL(e[WRI] > 0);
|
|
e[SUB] = dds_create_subscriber(e[PAR], NULL, NULL);
|
|
CU_ASSERT_FATAL(e[SUB] > 0);
|
|
e[REA] = dds_create_reader(e[SUB], e[TOP], NULL, NULL);
|
|
CU_ASSERT_FATAL(e[REA] > 0);
|
|
e[RCD] = dds_create_readcondition(e[REA], DDS_ANY_STATE);
|
|
CU_ASSERT_FATAL(e[RCD] > 0);
|
|
e[BAD] = 314159265;
|
|
}
|
|
|
|
static void
|
|
teardown(void)
|
|
{
|
|
for(unsigned i = (sizeof e / sizeof *e); i > 0; i--) {
|
|
dds_delete(e[i - 1]);
|
|
}
|
|
}
|
|
|
|
/*************************************************************************************************/
|
|
|
|
|
|
|
|
CU_Test(ddsc_unsupported, dds_begin_end_coherent, .init = setup, .fini = teardown)
|
|
{
|
|
dds_return_t result;
|
|
static struct index_result pars[] = {
|
|
{PUB, DDS_RETCODE_UNSUPPORTED},
|
|
{WRI, DDS_RETCODE_UNSUPPORTED},
|
|
{SUB, DDS_RETCODE_UNSUPPORTED},
|
|
{REA, DDS_RETCODE_UNSUPPORTED},
|
|
{BAD, DDS_RETCODE_BAD_PARAMETER}
|
|
};
|
|
|
|
for (int i=0; i < 5; i++) {
|
|
result = dds_begin_coherent(e[pars[i].index]);
|
|
CU_ASSERT_EQUAL(dds_err_nr(result), pars[i].exp_res);
|
|
result = dds_end_coherent(e[pars[i].index]);
|
|
CU_ASSERT_EQUAL(dds_err_nr(result), pars[i].exp_res);
|
|
}
|
|
}
|
|
|
|
CU_Test(ddsc_unsupported, dds_wait_for_acks, .init = setup, .fini = teardown)
|
|
{
|
|
dds_return_t result;
|
|
static struct index_result pars[] = {
|
|
{PUB, DDS_RETCODE_UNSUPPORTED},
|
|
{WRI, DDS_RETCODE_UNSUPPORTED},
|
|
{BAD, DDS_RETCODE_BAD_PARAMETER}
|
|
};
|
|
|
|
for (int i=0; i< 3; i++) {
|
|
result = dds_wait_for_acks(e[pars[i].index], 0);
|
|
CU_ASSERT_EQUAL(dds_err_nr(result), pars[i].exp_res);
|
|
}
|
|
}
|
|
|
|
CU_Test(ddsc_unsupported, dds_suspend_resume, .init = setup, .fini = teardown)
|
|
{
|
|
dds_return_t result;
|
|
static struct index_result pars[] = {
|
|
{PUB, DDS_RETCODE_UNSUPPORTED},
|
|
{WRI, DDS_RETCODE_ILLEGAL_OPERATION},
|
|
{BAD, DDS_RETCODE_BAD_PARAMETER}
|
|
};
|
|
|
|
for (int i=0; i< 3; i++) {
|
|
result = dds_suspend(e[pars[i].index]);
|
|
CU_ASSERT_EQUAL(dds_err_nr(result), pars[i].exp_res);
|
|
result = dds_resume(e[pars[i].index]);
|
|
CU_ASSERT_EQUAL(dds_err_nr(result), pars[i].exp_res);
|
|
}
|
|
}
|
|
|
|
CU_Test(ddsc_unsupported, dds_get_instance_handle, .init = setup, .fini = teardown)
|
|
{
|
|
dds_return_t result;
|
|
dds_instance_handle_t ih;
|
|
static struct index_result pars[] = {
|
|
{TOP, DDS_RETCODE_ILLEGAL_OPERATION}, /* TODO: Shouldn't this be either supported or unsupported? */
|
|
{PUB, DDS_RETCODE_UNSUPPORTED},
|
|
{SUB, DDS_RETCODE_UNSUPPORTED},
|
|
{RCD, DDS_RETCODE_ILLEGAL_OPERATION},
|
|
{BAD, DDS_RETCODE_BAD_PARAMETER}
|
|
};
|
|
|
|
for (int i=0; i < 5; i++) {
|
|
result = dds_get_instance_handle(e[pars[i].index], &ih);
|
|
CU_ASSERT_EQUAL(dds_err_nr(result), pars[i].exp_res);
|
|
}
|
|
}
|
|
|
|
CU_Test(ddsc_unsupported, dds_set_qos, .init = setup, .fini = teardown)
|
|
{
|
|
dds_return_t result;
|
|
dds_qos_t *qos;
|
|
static struct index_result pars[] = {
|
|
{PAR, DDS_RETCODE_UNSUPPORTED},
|
|
{TOP, DDS_RETCODE_UNSUPPORTED},
|
|
{PUB, DDS_RETCODE_UNSUPPORTED},
|
|
{WRI, DDS_RETCODE_UNSUPPORTED},
|
|
{SUB, DDS_RETCODE_UNSUPPORTED},
|
|
{REA, DDS_RETCODE_UNSUPPORTED},
|
|
{RCD, DDS_RETCODE_ILLEGAL_OPERATION},
|
|
{BAD, DDS_RETCODE_BAD_PARAMETER}
|
|
};
|
|
|
|
qos = dds_create_qos();
|
|
for (int i=0; i < 8;i++) {
|
|
result = dds_set_qos(e[pars[i].index], qos);
|
|
CU_ASSERT_EQUAL(dds_err_nr(result), pars[i].exp_res);
|
|
}
|
|
dds_delete_qos(qos);
|
|
}
|