Allow domain/cyclonedds as waitset/guardcond owner

Signed-off-by: Erik Boasson <eb@ilities.com>
This commit is contained in:
Erik Boasson 2019-08-28 15:01:13 +02:00 committed by eboasson
parent 0b12ff5cfc
commit 6da50bdbae
5 changed files with 287 additions and 17 deletions

View file

@ -11,6 +11,7 @@
*/
#include <assert.h>
#include <string.h>
#include "dds__init.h"
#include "dds__reader.h"
#include "dds__guardcond.h"
#include "dds__participant.h"
@ -28,22 +29,45 @@ const struct dds_entity_deriver dds_entity_deriver_guardcondition = {
.validate_status = dds_entity_deriver_dummy_validate_status
};
dds_entity_t dds_create_guardcondition (dds_entity_t participant)
dds_entity_t dds_create_guardcondition (dds_entity_t owner)
{
dds_participant *pp;
dds_entity *e;
dds_return_t rc;
if ((rc = dds_participant_lock (participant, &pp)) != DDS_RETCODE_OK)
/* If the owner is any ordinary (allowed) entity, the library is already initialised and calling
init here is cheap. If it is DDS_CYCLONEDDS_HANDLE, we may have to initialise the library, so
have to call it. If it is some bogus value and the library is not initialised yet ... so be
it. Naturally, this requires us to call delete on DDS_CYCLONEDDS_HANDLE afterward. */
if ((rc = dds_init ()) < 0)
return rc;
else
if ((rc = dds_entity_lock (owner, DDS_KIND_DONTCARE, &e)) != DDS_RETCODE_OK)
goto err_entity_lock;
switch (dds_entity_kind (e))
{
dds_guardcond *gcond = dds_alloc (sizeof (*gcond));
dds_entity_t hdl = dds_entity_init (&gcond->m_entity, &pp->m_entity, DDS_KIND_COND_GUARD, NULL, NULL, 0);
gcond->m_entity.m_iid = ddsi_iid_gen ();
dds_entity_register_child (&pp->m_entity, &gcond->m_entity);
dds_participant_unlock (pp);
return hdl;
case DDS_KIND_CYCLONEDDS:
case DDS_KIND_DOMAIN:
case DDS_KIND_PARTICIPANT:
break;
default:
rc = DDS_RETCODE_ILLEGAL_OPERATION;
goto err_entity_kind;
}
dds_guardcond *gcond = dds_alloc (sizeof (*gcond));
dds_entity_t hdl = dds_entity_init (&gcond->m_entity, e, DDS_KIND_COND_GUARD, NULL, NULL, 0);
gcond->m_entity.m_iid = ddsi_iid_gen ();
dds_entity_register_child (e, &gcond->m_entity);
dds_entity_unlock (e);
dds_delete (DDS_CYCLONEDDS_HANDLE);
return hdl;
err_entity_kind:
dds_entity_unlock (e);
err_entity_lock:
dds_delete (DDS_CYCLONEDDS_HANDLE);
return rc;
}
dds_return_t dds_set_guardcondition (dds_entity_t condition, bool triggered)

View file

@ -17,6 +17,7 @@
#include "dds__participant.h"
#include "dds__querycond.h"
#include "dds__readcond.h"
#include "dds__init.h"
#include "dds__rhc.h"
#include "dds/ddsi/ddsi_iid.h"
@ -112,24 +113,48 @@ const struct dds_entity_deriver dds_entity_deriver_waitset = {
.validate_status = dds_entity_deriver_dummy_validate_status
};
dds_entity_t dds_create_waitset (dds_entity_t participant)
dds_entity_t dds_create_waitset (dds_entity_t owner)
{
dds_entity_t hdl;
dds_participant *par;
dds_entity *e;
dds_return_t rc;
if ((rc = dds_participant_lock (participant, &par)) != DDS_RETCODE_OK)
/* If the owner is any ordinary (allowed) entity, the library is already initialised and calling
init here is cheap. If it is DDS_CYCLONEDDS_HANDLE, we may have to initialise the library, so
have to call it. If it is some bogus value and the library is not initialised yet ... so be
it. Naturally, this requires us to call delete on DDS_CYCLONEDDS_HANDLE afterward. */
if ((rc = dds_init ()) < 0)
return rc;
if ((rc = dds_entity_lock (owner, DDS_KIND_DONTCARE, &e)) != DDS_RETCODE_OK)
goto err_entity_lock;
switch (dds_entity_kind (e))
{
case DDS_KIND_CYCLONEDDS:
case DDS_KIND_DOMAIN:
case DDS_KIND_PARTICIPANT:
break;
default:
rc = DDS_RETCODE_ILLEGAL_OPERATION;
goto err_entity_kind;
}
dds_waitset *waitset = dds_alloc (sizeof (*waitset));
hdl = dds_entity_init (&waitset->m_entity, &par->m_entity, DDS_KIND_WAITSET, NULL, NULL, 0);
dds_entity_t hdl = dds_entity_init (&waitset->m_entity, e, DDS_KIND_WAITSET, NULL, NULL, 0);
waitset->m_entity.m_iid = ddsi_iid_gen ();
dds_entity_register_child (&par->m_entity, &waitset->m_entity);
dds_entity_register_child (e, &waitset->m_entity);
waitset->nentities = 0;
waitset->ntriggered = 0;
waitset->entities = NULL;
dds_participant_unlock (par);
dds_entity_unlock (e);
dds_delete (DDS_CYCLONEDDS_HANDLE);
return hdl;
err_entity_kind:
dds_entity_unlock (e);
err_entity_lock:
dds_delete (DDS_CYCLONEDDS_HANDLE);
return rc;
}
dds_return_t dds_waitset_get_entities (dds_entity_t waitset, dds_entity_t *entities, size_t size)

View file

@ -31,6 +31,7 @@ set(ddsc_test_sources
"publisher.c"
"qos.c"
"querycondition.c"
"guardcondition.c"
"readcondition.c"
"reader.c"
"reader_iterator.c"

View file

@ -0,0 +1,187 @@
/*
* 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 "RoundTrip.h"
#include "dds/ddsrt/cdtors.h"
#include "dds/ddsrt/misc.h"
#include "dds/ddsrt/process.h"
#include "dds/ddsrt/threads.h"
#include "dds/ddsrt/atomics.h"
#include "dds/ddsrt/time.h"
CU_Test (ddsc_guardcond_create, cyclonedds)
{
dds_entity_t gc;
dds_return_t rc;
/* Expect an uninitialised library */
rc = dds_get_parent (DDS_CYCLONEDDS_HANDLE);
CU_ASSERT_FATAL (rc == DDS_RETCODE_PRECONDITION_NOT_MET);
gc = dds_create_guardcondition (DDS_CYCLONEDDS_HANDLE);
CU_ASSERT_FATAL (gc > 0);
rc = dds_delete (DDS_CYCLONEDDS_HANDLE);
CU_ASSERT_FATAL (rc == 0);
/* And the same afterward */
rc = dds_get_parent (DDS_CYCLONEDDS_HANDLE);
CU_ASSERT_FATAL (rc == DDS_RETCODE_PRECONDITION_NOT_MET);
}
CU_Test (ddsc_guardcond_create, domain)
{
dds_entity_t par, dom, gc;
dds_return_t rc;
par = dds_create_participant (0, NULL, NULL);
CU_ASSERT_FATAL (par > 0);
dom = dds_get_parent (par);
CU_ASSERT_FATAL (dom > 0);
gc = dds_create_guardcondition (dom);
CU_ASSERT_FATAL (gc > 0);
rc = dds_delete (dom);
CU_ASSERT_FATAL (rc == 0);
}
CU_Test (ddsc_guardcond_create, participant)
{
dds_entity_t par, gc;
dds_return_t rc;
par = dds_create_participant (0, NULL, NULL);
CU_ASSERT_FATAL (par > 0);
gc = dds_create_guardcondition (par);
CU_ASSERT_FATAL (gc > 0);
rc = dds_delete (par);
CU_ASSERT_FATAL (rc == 0);
}
CU_Test (ddsc_guardcond, set_trigger)
{
dds_entity_t par, gc;
dds_return_t rc;
bool trig;
par = dds_create_participant (0, NULL, NULL);
CU_ASSERT_FATAL (par > 0);
gc = dds_create_guardcondition (par);
CU_ASSERT_FATAL (gc > 0);
rc = dds_read_guardcondition (gc, &trig);
CU_ASSERT_FATAL (rc == 0);
CU_ASSERT (!trig);
rc = dds_set_guardcondition (gc, true);
CU_ASSERT_FATAL (rc == 0);
rc = dds_read_guardcondition (gc, &trig);
CU_ASSERT_FATAL (rc == 0);
CU_ASSERT (trig);
rc = dds_delete (par);
CU_ASSERT_FATAL (rc == 0);
}
CU_Test (ddsc_guardcond, take_trigger)
{
dds_entity_t par, gc;
dds_return_t rc;
bool trig;
par = dds_create_participant (0, NULL, NULL);
CU_ASSERT_FATAL (par > 0);
gc = dds_create_guardcondition (par);
CU_ASSERT_FATAL (gc > 0);
rc = dds_read_guardcondition (gc, &trig);
CU_ASSERT_FATAL (rc == 0);
CU_ASSERT (!trig);
rc = dds_set_guardcondition (gc, true);
CU_ASSERT_FATAL (rc == 0);
rc = dds_take_guardcondition (gc, &trig);
CU_ASSERT_FATAL (rc == 0);
CU_ASSERT (trig);
rc = dds_read_guardcondition (gc, &trig);
CU_ASSERT_FATAL (rc == 0);
CU_ASSERT (!trig);
rc = dds_delete (par);
CU_ASSERT_FATAL (rc == 0);
}
CU_Test (ddsc_guardcond, waitset)
{
dds_entity_t par, gc, ws;
dds_attach_t xs[1];
dds_return_t rc;
par = dds_create_participant (0, NULL, NULL);
CU_ASSERT_FATAL (par > 0);
gc = dds_create_guardcondition (par);
CU_ASSERT_FATAL (gc > 0);
ws = dds_create_waitset (par);
CU_ASSERT_FATAL (ws > 0);
rc = dds_waitset_attach (ws, gc, gc);
CU_ASSERT_FATAL (rc == 0);
/* guard cond not triggered: waitset should return 0 */
rc = dds_waitset_wait (ws, xs, 1, 0);
CU_ASSERT (rc == 0);
rc = dds_set_guardcondition (gc, true);
CU_ASSERT_FATAL (rc == 0);
/* guard triggered: waitset should return it */
rc = dds_waitset_wait (ws, xs, 1, 0);
CU_ASSERT (rc == 1);
CU_ASSERT (xs[0] == gc);
rc = dds_delete (par);
CU_ASSERT_FATAL (rc == 0);
}
struct guardcond_thread_arg {
dds_entity_t gc;
dds_return_t ret;
};
static uint32_t guardcond_thread (void *varg)
{
struct guardcond_thread_arg *arg = varg;
/* 200ms sleep is hopefully always long enough for the main thread to
enter wait() and block; a further 800ms (see wait call) similarly
for the guard condition to actually trigger it. */
dds_sleepfor (DDS_MSECS (200));
arg->ret = dds_set_guardcondition (arg->gc, true);
return 0;
}
CU_Test (ddsc_guardcond, waitset_thread)
{
dds_entity_t par, gc, ws;
dds_attach_t xs[1];
dds_return_t rc;
ddsrt_thread_t tid;
ddsrt_threadattr_t tattr;
par = dds_create_participant (0, NULL, NULL);
CU_ASSERT_FATAL (par > 0);
gc = dds_create_guardcondition (par);
CU_ASSERT_FATAL (gc > 0);
ws = dds_create_waitset (par);
CU_ASSERT_FATAL (ws > 0);
rc = dds_waitset_attach (ws, gc, gc);
CU_ASSERT_FATAL (rc == 0);
struct guardcond_thread_arg arg = { .gc = gc };
ddsrt_threadattr_init (&tattr);
rc = ddsrt_thread_create (&tid, "guardcond_thread", &tattr, guardcond_thread, &arg);
CU_ASSERT_FATAL (rc == 0);
rc = dds_waitset_wait (ws, xs, 1, DDS_SECS (1));
CU_ASSERT (rc == 1);
CU_ASSERT (xs[0] == gc);
rc = ddsrt_thread_join (tid, NULL);
CU_ASSERT_FATAL (rc == 0);
CU_ASSERT_FATAL (arg.ret == 0);
rc = dds_delete (par);
CU_ASSERT_FATAL (rc == 0);
}

View file

@ -256,6 +256,39 @@ CU_Theory((dds_entity_t *par), ddsc_waitset_create, non_participants, .init=ddsc
}
/*************************************************************************************************/
/*************************************************************************************************/
CU_Test (ddsc_waitset_create, domain)
{
dds_entity_t par, dom, ws;
dds_return_t rc;
par = dds_create_participant (0, NULL, NULL);
CU_ASSERT_FATAL (par > 0);
dom = dds_get_parent (par);
CU_ASSERT_FATAL (dom > 0);
ws = dds_create_waitset (dom);
CU_ASSERT_FATAL (ws > 0);
rc = dds_delete (dom);
CU_ASSERT_FATAL (rc == 0);
}
/*************************************************************************************************/
/*************************************************************************************************/
CU_Test (ddsc_waitset_create, cyclonedds)
{
dds_entity_t ws;
dds_return_t rc;
/* Expect an uninitialised library */
rc = dds_get_parent (DDS_CYCLONEDDS_HANDLE);
CU_ASSERT_FATAL (rc == DDS_RETCODE_PRECONDITION_NOT_MET);
ws = dds_create_waitset (DDS_CYCLONEDDS_HANDLE);
CU_ASSERT_FATAL (ws > 0);
rc = dds_delete (DDS_CYCLONEDDS_HANDLE);
CU_ASSERT_FATAL (rc == 0);
/* And the same afterward */
rc = dds_get_parent (DDS_CYCLONEDDS_HANDLE);
CU_ASSERT_FATAL (rc == DDS_RETCODE_PRECONDITION_NOT_MET);
}
/*************************************************************************************************/
/**************************************************************************************************