static struct cfgelem shmem_cfgelems[] = { BOOL("Enable", NULL, 1, "false", MEMBER(enable_shm), FUNCTIONS(0, uf_boolean, 0, pf_boolean), DESCRIPTION("<p>This element allows to enable shared memory in Cyclone DDS.</p>")), STRING("Locator", NULL, 1, "", MEMBER(shm_locator), FUNCTIONS(0, uf_string, ff_free, pf_string), DESCRIPTION( "<p>Explicitly set the Iceoryx locator used by Cyclone to check whether " "a pair of processes is attached to the same Iceoryx shared memory. The " "default is to use one of the MAC addresses of the machine, which should " "work well in most cases.</p>" )), STRING("Prefix", NULL, 1, "DDS_CYCLONE", MEMBER(iceoryx_service), FUNCTIONS(0, uf_string, ff_free, pf_string), DESCRIPTION( "<p>Override the Iceoryx service name used by Cyclone.</p>" )), ENUM("LogLevel", NULL, 1, "info", MEMBER(shm_log_lvl), ...
四个配置项:Enable(默认 false)、Locator(同机判定地址,默认取 MAC)、Prefix(iceoryx CaPro service 名,默认 DDS_CYCLONE)、LogLevel。
static int iceoryx_init (struct ddsi_domaingv *gv) { shm_set_loglevel(gv->config.shm_log_lvl);
char *sptr; ddsrt_asprintf (&sptr, "iceoryx_rt_%"PRIdPID"_%"PRId64, ddsrt_getpid (), gv->tstart.v); GVLOG (DDS_LC_SHM, "Current process name for iceoryx is %s\n", sptr); iox_runtime_init (sptr); free(sptr);
// FIXME: this can be done more elegantly when properly supporting multiple transports if (ddsi_vnet_init (gv, "iceoryx", NN_LOCATOR_KIND_SHEM) < 0) return -1; ddsi_factory_find (gv, "iceoryx")->m_enable = true;
SHEM locator 的地址如何来:未显式配置 SharedMemory/Locator 时取本机第一个非 loopback 网卡的 MAC 地址——它唯一标识”这台机器”,用于后续同机判定:
1 2 3 4 5 6 7 8
memset (gv->loc_iceoryx_addr.address, 0, sizeof (gv->loc_iceoryx_addr.address)); if (ddsrt_eth_get_mac_addr (gv->interfaces[if_index].name, gv->loc_iceoryx_addr.address)) { GVERROR ("Unable to get MAC address for iceoryx\n"); return -1; } gv->loc_iceoryx_addr.kind = NN_LOCATOR_KIND_SHEM; gv->loc_iceoryx_addr.port = 0;
#ifdef DDS_HAS_SHM // SHM_TODO: We avoid sending packet while data is SHMEM. // I'm not sure whether this is correct or not. if (!gv->mute && loc->c.kind != NN_LOCATOR_KIND_SHEM) #else if (!gv->mute)
// check necessary condition: fixed size data type OR serializing into shared // memory is available if (!tp->m_stype->fixed_size && (!tp->m_stype->ops->get_serialized_size || !tp->m_stype->ops->serialize_into)) { return false; }
// only VOLATILE or TRANSIENT LOCAL if(!(qos->durability.kind == DDS_DURABILITY_VOLATILE || qos->durability.kind == DDS_DURABILITY_TRANSIENT_LOCAL)) { return false; }
// only KEEP LAST if(qos->history.kind != DDS_HISTORY_KEEP_LAST) { return false; }
#ifdef DDS_HAS_SHM if (wr->m_wr->has_iceoryx) { DDS_CLOG (DDS_LC_SHM, &wr->m_entity.m_domain->gv.logconfig, "Writer's topic name will be DDS:Cyclone:%s\n", wr->m_topic->m_name); iox_pub_options_t opts = create_iox_pub_options(wqos);
// NB: This may fail due to icoeryx being out of internal resources for publishers // In this case terminate is called by iox_pub_init. // it is currently (iceoryx 2.0 and lower) not possible to change this to // e.g. return a nullptr and handle the error here. wr->m_iox_pub = iox_pub_init(&(iox_pub_storage_t){0}, gv->config.iceoryx_service, wr->m_topic->m_stype->type_name, wr->m_topic->m_name, &opts); memset(wr->m_iox_pub_loans, 0, sizeof(wr->m_iox_pub_loans)); } #endif
// NB: If we cannot take the chunk (sample) the user may lose data. // Since the subscriber queue can overflow and will evict the least recent sample. ... const iceoryx_header_t* ice_hdr = iceoryx_header_from_chunk(chunk);
// Get writer or proxy writer struct ddsi_entity_common * e = entidx_lookup_guid_untyped (gv->entity_index, &ice_hdr->guid); ... // Create struct ddsi_serdata struct ddsi_serdata* d = ddsi_serdata_from_iox(rd->m_topic->m_stype, ice_hdr->data_kind, &rd->m_iox_sub, chunk); d->timestamp.v = ice_hdr->tstamp; d->statusinfo = ice_hdr->statusinfo; ... ddsi_make_writer_info(&wrinfo, e, xqos, d->statusinfo); (void)ddsi_rhc_store(rd->m_rd->rhc, &wrinfo, d, tk);
if ((ret = dds_writer_lock(writer, &wr)) != DDS_RETCODE_OK) return ret;
// the loaning is only allowed if SHM is enabled correctly and if the type is // fixed if (wr->m_iox_pub && wr->m_topic->m_stype->fixed_size) { *sample = dds_writer_loan_chunk(wr, wr->m_topic->m_stype->iox_size); if (*sample == NULL) { ret = DDS_RETCODE_ERROR; // could not obtain a sample } } else { ret = DDS_RETCODE_UNSUPPORTED; } ...
// if the publisher can loan if (cdds_publisher->is_loaning_available) { auto sample_ptr = init_and_alloc_sample(cdds_publisher, cdds_publisher->sample_size); RET_NULL_X(sample_ptr, return RMW_RET_ERROR); *ros_message = sample_ptr; return RMW_RET_OK; } else { RMW_SET_ERROR_MSG("Borrowing loan for a non fixed type is not allowed"); return RMW_RET_ERROR; }
// if the publisher allow loaning if (cdds_publisher->is_loaning_available) { auto d = new serdata_rmw(cdds_publisher->sertype, ddsi_serdata_kind::SDK_DATA); d->iox_chunk = ros_message; // since we write the loaned chunk here, set the data state to raw shm_set_data_state(d->iox_chunk, IOX_CHUNK_CONTAINS_RAW_DATA); if (dds_writecdr(cdds_publisher->enth, d) >= 0) { return RMW_RET_OK;
非 POD 类型不能 loan,但 SHM 可用时序列化结果仍可写进共享内存(退化为”一次序列化 + 零网络拷贝”):
1 2 3 4 5 6 7
if (dds_is_shared_memory_available(pub->enth)) { auto sample_ptr = init_and_alloc_sample(pub, serialized_message->buffer_length); RET_NULL_X(sample_ptr, return RMW_RET_ERROR); memcpy(sample_ptr, serialized_message->buffer, serialized_message->buffer_length); shm_set_data_state(sample_ptr, IOX_CHUNK_CONTAINS_SERIALIZED_DATA); d->iox_chunk = sample_ptr; }
# 2. 打开 SHM 日志观察是否真的走了共享内存 export CYCLONEDDS_URI='<CycloneDDS><Domain><SharedMemory><Enable>true</Enable><LogLevel>verbose</LogLevel></SharedMemory><Tracing><Verbosity>config</Verbosity><OutputFile>stdout</OutputFile></Tracing></Domain></CycloneDDS>' # 日志中应出现 "My iceoryx address: ..."、"Writer's topic name will be DDS:Cyclone:<topic>"
正在加载留言…