Fix array keys on little-endian machines (#358)

* Fix array keys on little-endian machines

Signed-off-by: Erik Boasson <eb@ilities.com>

* Test for writing topics with an array as key

Signed-off-by: Erik Boasson <eb@ilities.com>
This commit is contained in:
eboasson 2019-12-13 14:18:31 +02:00 committed by GitHub
parent fc8d844519
commit 52d6e0be26
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 283 additions and 4 deletions

View file

@ -1288,9 +1288,12 @@ static void dds_stream_extract_key_from_key_prim_op (dds_istream_t * __restrict
#if DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN
static void dds_stream_swap_copy (void * __restrict vdst, const void * __restrict vsrc, uint32_t size, uint32_t num)
{
assert (size == 2 || size == 4 || size == 8);
assert (size == 1 || size == 2 || size == 4 || size == 8);
switch (size)
{
case 1:
memcpy (vdst, vsrc, num);
break;
case 2: {
const uint16_t *src = vsrc;
uint16_t *dst = vdst;
@ -1342,7 +1345,7 @@ static void dds_stream_extract_keyBE_from_key_prim_op (dds_istream_t * __restric
void const * const src = is->m_buffer + is->m_index;
void * const dst = os->x.m_buffer + os->x.m_index;
#if DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN
dds_stream_swap_copy (dst, src, num, align);
dds_stream_swap_copy (dst, src, align, num);
#else
memcpy (dst, src, num * align);
#endif
@ -1717,7 +1720,7 @@ static bool prtf_simple_array (char * __restrict *buf, size_t * __restrict bufsi
abort ();
break;
}
return cont;
return prtf (buf, bufsize, "}");
}
static bool dds_stream_print_sample1 (char * __restrict *buf, size_t * __restrict bufsize, dds_istream_t * __restrict is, const uint32_t * __restrict ops, bool add_braces);

View file

@ -14,6 +14,7 @@ include(CUnit)
idlc_generate(RoundTrip RoundTrip.idl)
idlc_generate(Space Space.idl)
idlc_generate(TypesArrayKey TypesArrayKey.idl)
idlc_generate(WriteTypes WriteTypes.idl)
set(ddsc_test_sources
"basic.c"
@ -51,6 +52,7 @@ set(ddsc_test_sources
"waitset.c"
"waitset_torture.c"
"write.c"
"write_various_types.c"
"writer.c")
add_cunit_executable(cunit_ddsc ${ddsc_test_sources})
@ -59,7 +61,7 @@ target_include_directories(
"$<BUILD_INTERFACE:${CMAKE_BINARY_DIR}/src/include/>"
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../../ddsc/src>"
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../../ddsi/include>")
target_link_libraries(cunit_ddsc PRIVATE RoundTrip Space TypesArrayKey ddsc)
target_link_libraries(cunit_ddsc PRIVATE RoundTrip Space TypesArrayKey WriteTypes ddsc)
# Setup environment for config-tests
get_test_property(CUnit_ddsc_config_simple_udp ENVIRONMENT CUnit_ddsc_config_simple_udp_env)

View file

@ -0,0 +1,25 @@
module WriteTypes {
struct a {
octet k[3];
unsigned long long ll;
};
#pragma keylist a k
struct b {
unsigned short k[3];
unsigned long long ll;
};
#pragma keylist b k
struct c {
unsigned long k[3];
unsigned long long ll;
};
#pragma keylist c k
struct d {
unsigned long long k[3];
unsigned long long ll;
};
#pragma keylist d k
};

View file

@ -0,0 +1,249 @@
/*
* 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 <assert.h>
#include <limits.h>
#include "dds/dds.h"
#include "CUnit/Theory.h"
#include "WriteTypes.h"
#include "dds/ddsrt/process.h"
#include "dds/ddsrt/threads.h"
#include "dds/ddsrt/environ.h"
#define DDS_DOMAINID_PUB 0
#define DDS_DOMAINID_SUB 1
#define DDS_CONFIG_NO_PORT_GAIN "${CYCLONEDDS_URI}${CYCLONEDDS_URI:+,}<Discovery><ExternalDomainId>0</ExternalDomainId></Discovery>"
#define DDS_CONFIG_NO_PORT_GAIN_LOG "${CYCLONEDDS_URI}${CYCLONEDDS_URI:+,}<Tracing><OutputFile>cyclonedds_writetypes_various.${CYCLONEDDS_DOMAIN_ID}.${CYCLONEDDS_PID}.log</OutputFile><Verbosity>finest</Verbosity></Tracing><Discovery><ExternalDomainId>0</ExternalDomainId></Discovery>"
static uint32_t g_topic_nr = 0;
static dds_entity_t g_pub_domain = 0;
static dds_entity_t g_pub_participant = 0;
static dds_entity_t g_pub_publisher = 0;
static dds_entity_t g_sub_domain = 0;
static dds_entity_t g_sub_participant = 0;
static dds_entity_t g_sub_subscriber = 0;
static char *create_topic_name (const char *prefix, uint32_t nr, char *name, size_t size)
{
/* Get unique g_topic name. */
ddsrt_pid_t pid = ddsrt_getpid ();
ddsrt_tid_t tid = ddsrt_gettid ();
(void) snprintf (name, size, "%s%d_pid%" PRIdPID "_tid%" PRIdTID "", prefix, nr, pid, tid);
return name;
}
static void writetypes_init(void)
{
/* Domains for pub and sub use a different domain id, but the portgain setting
* in configuration is 0, so that both domains will map to the same port number.
* This allows to create two domains in a single test process. */
char *conf_pub = ddsrt_expand_envvars (DDS_CONFIG_NO_PORT_GAIN, DDS_DOMAINID_PUB);
char *conf_sub = ddsrt_expand_envvars (DDS_CONFIG_NO_PORT_GAIN, DDS_DOMAINID_SUB);
g_pub_domain = dds_create_domain (DDS_DOMAINID_PUB, conf_pub);
g_sub_domain = dds_create_domain (DDS_DOMAINID_SUB, conf_sub);
dds_free (conf_pub);
dds_free (conf_sub);
g_pub_participant = dds_create_participant (DDS_DOMAINID_PUB, NULL, NULL);
CU_ASSERT_FATAL (g_pub_participant > 0);
g_sub_participant = dds_create_participant (DDS_DOMAINID_SUB, NULL, NULL);
CU_ASSERT_FATAL (g_sub_participant > 0);
g_pub_publisher = dds_create_publisher (g_pub_participant, NULL, NULL);
CU_ASSERT_FATAL (g_pub_publisher > 0);
g_sub_subscriber = dds_create_subscriber (g_sub_participant, NULL, NULL);
CU_ASSERT_FATAL (g_sub_subscriber > 0);
}
static void writetypes_fini (void)
{
dds_delete (g_sub_subscriber);
dds_delete (g_pub_publisher);
dds_delete (g_sub_participant);
dds_delete (g_pub_participant);
dds_delete (g_sub_domain);
dds_delete (g_pub_domain);
}
typedef bool (*compare_fn_t) (const void *a, const void *b);
#define ABCD_CMP(typ_) \
static bool typ_##_cmp (const void *va, const void *vb) \
{ \
const struct WriteTypes_##typ_ *a = va; \
const struct WriteTypes_##typ_ *b = vb; \
return a->k[0] == b->k[0] && a->k[1] == b->k[1] && a->k[2] == b->k[2] && a->ll == b->ll; \
}
ABCD_CMP (a)
ABCD_CMP (b)
ABCD_CMP (c)
ABCD_CMP (d)
#undef ABCD_CMP
struct sample {
bool in_result;
const void *data;
};
#define S(n) &(struct WriteTypes_##n)
static const struct sample a_samples[] = {
{ 1, S(a) { .k={1,2,3}, .ll = UINT64_C (0x1234567890abcdef) } },
{ 0, S(a) { .k={3,2,1}, .ll = UINT64_C (0) } },
{ 1, S(a) { .k={3,2,1}, .ll = UINT64_C (1) } },
};
static const struct sample b_samples[] = {
{ 1, S(b) { .k={1001,1002,1003}, .ll = UINT64_C (0x1234567890abcdef) } },
{ 0, S(b) { .k={1003,1002,1001}, .ll = UINT64_C (0) } },
{ 1, S(b) { .k={1003,1002,1001}, .ll = UINT64_C (1) } },
};
static const struct sample c_samples[] = {
{ 1, S(c) { .k={12340001,12340002,12340003}, .ll = UINT64_C (0x1234567890abcdef) } },
{ 0, S(c) { .k={12340003,12340002,12340001}, .ll = UINT64_C (0) } },
{ 1, S(c) { .k={12340003,12340002,12340001}, .ll = UINT64_C (1) } },
};
static const struct sample d_samples[] = {
{ 1, S(d) { .k={123400056780001,2,3}, .ll = UINT64_C (0x1234567890abcdef) } },
{ 0, S(d) { .k={123400056780003,2,1}, .ll = UINT64_C (0) } },
{ 1, S(d) { .k={123400056780003,2,1}, .ll = UINT64_C (1) } },
};
#undef S
#define T(n) &WriteTypes_##n##_desc
#define C(n) &n##_cmp
#define N(n) (sizeof (n##_samples) / sizeof (n##_samples[0]))
#define S(n) n##_samples
CU_TheoryDataPoints(ddsc_writetypes, various) = {
CU_DataPoints(const dds_topic_descriptor_t *, T(a), T(b), T(c), T(d)),
CU_DataPoints(compare_fn_t, C(a), C(b), C(c), C(d)),
CU_DataPoints(size_t, N(a), N(b), N(c), N(d)),
CU_DataPoints(const struct sample *, S(a), S(b), S(c), S(d)),
};
#undef S
#undef N
#undef C
#undef T
#define MAX_SAMPLES 5
CU_Theory((const dds_topic_descriptor_t *desc, compare_fn_t cmp, size_t nsamples, const struct sample *samples), ddsc_writetypes, various, .init = writetypes_init, .fini = writetypes_fini, .timeout = 10)
{
dds_entity_t pub_topic;
dds_entity_t sub_topic;
dds_entity_t reader;
dds_entity_t writer;
dds_qos_t *qos;
dds_return_t rc;
char name[100];
/* nsamples < MAX_SAMPLES so there is room for an invalid sample if we need it */
CU_ASSERT_FATAL (nsamples < MAX_SAMPLES);
qos = dds_create_qos ();
CU_ASSERT_FATAL (qos != NULL);
dds_qset_reliability (qos, DDS_RELIABILITY_RELIABLE, DDS_SECS (1));
dds_qset_writer_data_lifecycle (qos, false);
create_topic_name ("ddsc_writetypes_various", g_topic_nr++, name, sizeof name);
pub_topic = dds_create_topic (g_pub_participant, desc, name, qos, NULL);
CU_ASSERT_FATAL (pub_topic > 0);
sub_topic = dds_create_topic (g_sub_participant, desc, name, qos, NULL);
CU_ASSERT_FATAL (sub_topic > 0);
dds_delete_qos (qos);
reader = dds_create_reader (g_sub_participant, sub_topic, NULL, NULL);
CU_ASSERT_FATAL (reader > 0);
writer = dds_create_writer (g_pub_participant, pub_topic, NULL, NULL);
CU_ASSERT_FATAL (writer > 0);
/* simple-minded polling until reader/writer have matched each other */
while (1)
{
dds_publication_matched_status_t st;
rc = dds_get_publication_matched_status (writer, &st);
CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
if (st.current_count > 0)
break;
dds_sleepfor (DDS_MSECS (1));
}
while (1)
{
dds_subscription_matched_status_t st;
rc = dds_get_subscription_matched_status (reader, &st);
CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
if (st.current_count > 0)
break;
dds_sleepfor (DDS_MSECS (1));
}
/* write samples */
for (size_t i = 0; i < nsamples; i++) {
rc = dds_write (writer, samples[i].data);
CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
}
/* delete writer, wait until no matching writer: writer lingering should ensure the data
has been delivered at that point */
rc = dds_delete (writer);
CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
while (1)
{
dds_subscription_matched_status_t st;
rc = dds_get_subscription_matched_status (reader, &st);
CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
if (st.current_count == 0)
break;
dds_sleepfor (DDS_MSECS (1));
}
/* instances are unordered; this is a woefully inefficient way of comparing the sets,
but for the numbers of samples we do here, it really doesn't matter */
dds_sample_info_t si[MAX_SAMPLES];
void *xs[MAX_SAMPLES];
xs[0] = NULL;
int32_t n;
n = dds_read (reader, xs, si, MAX_SAMPLES, MAX_SAMPLES);
CU_ASSERT_FATAL (n > 0);
size_t nvalid = 0;
for (int32_t j = 0; j < n; j++)
{
if (si[j].valid_data)
nvalid++;
}
for (size_t i = 0; i < nsamples; i++)
{
if (samples[i].in_result)
{
/* sample must be present, erase it by marking it invalid */
int32_t j;
for (j = 0; j < n; j++)
if (si[j].valid_data && cmp (samples[i].data, xs[j]))
break;
CU_ASSERT (j < n);
si[j].valid_data = 0;
nvalid--;
}
}
/* all valid samples must be accounted for */
CU_ASSERT_FATAL (nvalid == 0);
rc = dds_return_loan (reader, xs, n);
CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
/* cleanup */
rc = dds_delete (reader);
CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
rc = dds_delete (sub_topic);
CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
rc = dds_delete (pub_topic);
CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
}