LCOV - code coverage report
Current view: top level - base_comm/resources/endpoints - jetty_context.cc (source / functions) Coverage Total Hit
Test: coverage.info Lines: 85.6 % 187 160
Test Date: 2026-08-25 19:18:03 Functions: 100.0 % 10 10

            Line data    Source code
       1              : /**
       2              :  * Copyright (c) 2025 Huawei Technologies Co., Ltd.
       3              :  * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
       4              :  * CANN Open Software License Agreement Version 2.0 (the "License").
       5              :  * Please refer to the License for details. You may not use this file except in compliance with the License.
       6              :  * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
       7              :  * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
       8              :  * See LICENSE in the root of the software repository for the full text of the License.
       9              :  */
      10              : 
      11              : #include "jetty_context.h"
      12              : #include "log.h"
      13              : #include "adapter_rts_common.h"
      14              : 
      15              : namespace hcomm {
      16              : namespace {
      17              : 
      18            4 :     bool IsSameRemoteJetty(const JettyContext::SharedRemoteJettyCtx& ctx, const uint8_t* remoteQpKey, uint32_t keySize)
      19              :     {
      20            4 :         return ctx.remoteQpKey.size() == keySize && std::memcmp(ctx.remoteQpKey.data(), remoteQpKey, keySize) == 0;
      21              :     }
      22              : } // namespace
      23              : 
      24           52 : JettyContext::~JettyContext()
      25              : {
      26           26 :     std::lock_guard<std::mutex> lk(mtx_);
      27           26 :     if (inner_.valid && inner_.handle != 0) {
      28            9 :         if (inner_.refCount == 0) {
      29              :             // 与 DevUbConnection::ReleaseResource 的 ctxValid 防御一致:进程退出/DeInit 阶段
      30              :             // RdmaHandleManager 可能已销毁,句柄可能已失效,用失效句柄 unimport/destroy 会崩溃。
      31            0 :             const bool rdmaValid = (inner_.rdmaHandle != nullptr)
      32            0 :                                    && Hccl::RdmaHandleManager::GetInstance().IsHandleValid(
      33            0 :                                        static_cast<Hccl::RdmaHandle>(inner_.rdmaHandle));
      34            0 :             if (!rdmaValid) {
      35            0 :                 HCCL_WARNING(
      36              :                     "[JettyContext][~JettyContext] shared jetty still valid on destroy but rdmaHandle "
      37              :                     "invalid, skip unimport/destroy to avoid using invalid handle, handle[%llu].",
      38              :                     static_cast<unsigned long long>(inner_.handle));
      39            0 :                 return;
      40              :             }
      41            0 :             HCCL_WARNING(
      42              :                 "[JettyContext][~JettyContext] shared jetty still valid on destroy, handle[%llu], "
      43              :                 "force destroy.",
      44              :                 static_cast<unsigned long long>(inner_.handle));
      45            0 :             UnimportSharedRemoteJettys(inner_);
      46            0 :             DestroyJettyResources(inner_);
      47              :         } else {
      48            9 :             HCCL_WARNING(
      49              :                 "[JettyContext][~JettyContext] shared jetty still in use, refCount[%u], handle[%llu], "
      50              :                 "skip destroy to avoid use-after-free.",
      51              :                 inner_.refCount, static_cast<unsigned long long>(inner_.handle));
      52              :         }
      53              :     }
      54           52 : }
      55              : 
      56           27 : HcclResult JettyContext::Acquire(const std::function<HcclResult(Ctx&)>& provideCtx, Ctx& outCtx)
      57              : {
      58              :     // 第一段(持锁):检查是否已创建或正在创建。已创建则 refCount++ 返回;未创建则标记 creating。
      59              :     // 超时上限 32s(覆盖 provideCtx 内部 16s jetty 创建 + 余量),避免创建线程异常崩溃后其他线程永久阻塞。
      60              :     {
      61           27 :         std::unique_lock<std::mutex> lk(mtx_);
      62           27 :         if (!cv_.wait_for(lk, std::chrono::seconds(32), [this] {
      63           28 :                 return inner_.valid || !inner_.creating;
      64              :             })) {
      65            0 :             HCCL_ERROR("[JettyContext][Acquire] wait for shared jetty creation timeout[32s].");
      66            0 :             return HCCL_E_TIMEOUT;
      67              :         }
      68           27 :         if (inner_.valid) {
      69           10 :             inner_.refCount++;
      70           10 :             outCtx = InnerToCtx(inner_);
      71           10 :             HCCL_INFO(
      72              :                 "[JettyContext][Acquire] reuse shared jetty, handle[%llu], refCount[%u]",
      73              :                 static_cast<unsigned long long>(outCtx.handle), inner_.refCount);
      74           10 :             return HCCL_SUCCESS;
      75              :         }
      76              :         // 抢占创建权
      77           17 :         inner_.creating = true;
      78           27 :     }
      79              : 
      80              :     // 第二段(无锁):执行首次创建回调(含网络建链 I/O,可能耗时数秒)。
      81              :     // 创建期间不持锁,其他线程的 Acquire 在 cv_ 上等待,Release 不被阻塞。
      82           17 :     Ctx createdCtx;
      83           17 :     HcclResult createRet = provideCtx(createdCtx);
      84           16 :     if (createRet != HCCL_SUCCESS) {
      85            1 :         std::lock_guard<std::mutex> lk(mtx_);
      86            1 :         inner_.creating = false;
      87            1 :         cv_.notify_all();
      88            1 :         HCCL_ERROR("[JettyContext][Acquire] provideCtx failed, ret[%d].", createRet);
      89            1 :         return createRet;
      90            1 :     }
      91              : 
      92              :     // 第三段(持锁):写入缓存,清除 creating 标记,设置 refCount=1。
      93              :     {
      94           15 :         std::lock_guard<std::mutex> lk(mtx_);
      95           15 :         inner_.handle = createdCtx.handle;
      96           15 :         inner_.handlePtr = createdCtx.handlePtr;
      97           15 :         inner_.jettyId = createdCtx.jettyId;
      98           15 :         inner_.sqBuffVa = createdCtx.sqBuffVa;
      99           15 :         inner_.dbAddr = createdCtx.dbAddr;
     100           15 :         inner_.keySize = createdCtx.keySize;
     101           15 :         inner_.sqDepth = createdCtx.sqDepth;
     102           15 :         inner_.sqPiPtr = createdCtx.sqPiPtr;
     103           15 :         inner_.sqCiPtr = createdCtx.sqCiPtr;
     104           15 :         inner_.cqPiPtr = createdCtx.cqPiPtr;
     105           15 :         inner_.cqCiPtr = createdCtx.cqCiPtr;
     106           15 :         inner_.queueIndexMemSize = createdCtx.queueIndexMemSize;
     107           15 :         inner_.rdmaHandle = createdCtx.rdmaHandle;
     108           15 :         inner_.jfcHandle = createdCtx.jfcHandle;
     109           15 :         inner_.cqInfo = createdCtx.cqInfo;
     110           15 :         inner_.localPsn = createdCtx.localPsn;
     111           15 :         if (createdCtx.keySize > 0 && createdCtx.keySize <= Hccl::HRT_UB_QP_KEY_MAX_LEN) {
     112              :             errno_t cpyRet
     113           10 :                 = memcpy_s(inner_.localQpKey, Hccl::HRT_UB_QP_KEY_MAX_LEN, createdCtx.localQpKey, createdCtx.keySize);
     114           10 :             if (cpyRet != EOK) {
     115              :                 // memcpy_s 失败:inner_ 已写入部分字段(handle/PI·CI 指针等)但 valid 仍为 false,
     116              :                 // 需销毁已写入的 device 资源避免泄漏,再清空 inner_ 让其他线程可重新创建。
     117            0 :                 DestroyJettyResources(inner_);
     118            0 :                 inner_ = Inner{};
     119            0 :                 inner_.creating = false;
     120            0 :                 cv_.notify_all();
     121            0 :                 HCCL_ERROR("[JettyContext][Acquire] memcpy_s localQpKey failed, ret[%d].", cpyRet);
     122            0 :                 return HCCL_E_INTERNAL;
     123              :             }
     124              :         }
     125           15 :         inner_.valid = true;
     126           15 :         inner_.creating = false;
     127           15 :         inner_.refCount = 1;
     128           15 :         outCtx = InnerToCtx(inner_);
     129           15 :         cv_.notify_all();
     130           15 :     }
     131           15 :     HCCL_INFO(
     132              :         "[JettyContext][Acquire] created shared jetty, handle[%llu]", static_cast<unsigned long long>(outCtx.handle));
     133           15 :     return HCCL_SUCCESS;
     134              : }
     135              : 
     136           11 : HcclResult JettyContext::Release()
     137              : {
     138           11 :     std::lock_guard<std::mutex> lk(mtx_);
     139           11 :     if (!inner_.valid) {
     140            3 :         HCCL_WARNING("[JettyContext][Release] shared jetty already invalid, skip release.");
     141            3 :         return HCCL_SUCCESS;
     142              :     }
     143            8 :     if (inner_.refCount == 0) {
     144            1 :         HCCL_WARNING("[JettyContext][Release] refCount already 0, skip release.");
     145            1 :         return HCCL_SUCCESS;
     146              :     }
     147            7 :     inner_.refCount--;
     148            7 :     HCCL_INFO(
     149              :         "[JettyContext][Release] release shared jetty, handle[%llu], refCount[%u]",
     150              :         static_cast<unsigned long long>(inner_.handle), inner_.refCount);
     151            7 :     if (inner_.refCount == 0) {
     152            5 :         UnimportSharedRemoteJettys(inner_);
     153            5 :         DestroyJettyResources(inner_);
     154            5 :         inner_ = Inner{};
     155              :     }
     156            7 :     return HCCL_SUCCESS;
     157           11 : }
     158              : 
     159            9 : HcclResult JettyContext::AcquireSharedRemoteJetty(
     160              :     const uint8_t* remoteQpKey, uint32_t keySize, bool& needImport, uint64_t& handle, void*& handlePtr, uint32_t& tpn)
     161              : {
     162            9 :     CHK_PTR_NULL(remoteQpKey);
     163            8 :     CHK_PRT_RET(
     164              :         keySize == 0 || keySize > Hccl::HRT_UB_QP_KEY_MAX_LEN,
     165              :         HCCL_ERROR("[%s] invalid keySize[%u].", __func__, keySize), HCCL_E_PARA);
     166              : 
     167            7 :     std::lock_guard<std::mutex> lk(mtx_);
     168            7 :     CHK_PRT_RET(!inner_.valid, HCCL_ERROR("[%s] shared local jetty is invalid.", __func__), HCCL_E_INTERNAL);
     169              : 
     170            6 :     needImport = false;
     171            6 :     handle = 0;
     172            6 :     handlePtr = nullptr;
     173            6 :     tpn = 0;
     174            6 :     for (const auto& remoteCtx : inner_.remoteJettys) {
     175            2 :         if (!IsSameRemoteJetty(remoteCtx, remoteQpKey, keySize)) {
     176            0 :             continue;
     177              :         }
     178            2 :         if (remoteCtx.ready) {
     179            1 :             handle = remoteCtx.handle;
     180            1 :             handlePtr = remoteCtx.handlePtr;
     181            1 :             tpn = remoteCtx.tpn;
     182            1 :             HCCL_INFO(
     183              :                 "[%s] reuse shared remote jetty, handle[%llu], tpn[%u].", __func__,
     184              :                 static_cast<unsigned long long>(handle), tpn);
     185              :         }
     186            2 :         return HCCL_SUCCESS;
     187              :     }
     188              : 
     189            4 :     SharedRemoteJettyCtx remoteCtx;
     190            4 :     remoteCtx.remoteQpKey.assign(remoteQpKey, remoteQpKey + keySize);
     191            4 :     inner_.remoteJettys.push_back(std::move(remoteCtx));
     192            4 :     needImport = true;
     193            4 :     HCCL_INFO("[%s] reserve shared remote jetty import.", __func__);
     194            4 :     return HCCL_SUCCESS;
     195            7 : }
     196              : 
     197            7 : HcclResult JettyContext::PublishSharedRemoteJetty(
     198              :     const uint8_t* remoteQpKey, uint32_t keySize, uint64_t handle, void* handlePtr, uint32_t tpn)
     199              : {
     200            7 :     CHK_PTR_NULL(remoteQpKey);
     201            6 :     CHK_PTR_NULL(handlePtr);
     202            5 :     CHK_PRT_RET(
     203              :         keySize == 0 || keySize > Hccl::HRT_UB_QP_KEY_MAX_LEN || handle == 0,
     204              :         HCCL_ERROR(
     205              :             "[%s] invalid params, keySize[%u], handle[%llu].", __func__, keySize,
     206              :             static_cast<unsigned long long>(handle)),
     207              :         HCCL_E_PARA);
     208              : 
     209            3 :     std::lock_guard<std::mutex> lk(mtx_);
     210            3 :     for (auto& remoteCtx : inner_.remoteJettys) {
     211            2 :         if (!IsSameRemoteJetty(remoteCtx, remoteQpKey, keySize)) {
     212            0 :             continue;
     213              :         }
     214            2 :         remoteCtx.handle = handle;
     215            2 :         remoteCtx.handlePtr = handlePtr;
     216            2 :         remoteCtx.tpn = tpn;
     217            2 :         remoteCtx.ready = true;
     218            2 :         HCCL_INFO(
     219              :             "[%s] publish shared remote jetty, handle[%llu], tpn[%u].", __func__,
     220              :             static_cast<unsigned long long>(handle), tpn);
     221            2 :         return HCCL_SUCCESS;
     222              :     }
     223            1 :     HCCL_ERROR("[%s] shared remote jetty reservation not found.", __func__);
     224            1 :     return HCCL_E_NOT_FOUND;
     225            3 : }
     226              : 
     227            5 : void JettyContext::UnimportSharedRemoteJettys(Inner& inner)
     228              : {
     229            5 :     if (inner.rdmaHandle == nullptr) {
     230            4 :         return;
     231              :     }
     232            1 :     for (auto& remoteCtx : inner.remoteJettys) {
     233            0 :         if (!remoteCtx.ready || remoteCtx.handle == 0) {
     234            0 :             continue;
     235              :         }
     236            0 :         Hccl::HrtRaUbUnimportJetty(
     237            0 :             static_cast<Hccl::RdmaHandle>(inner.rdmaHandle), static_cast<Hccl::TargetJettyHandle>(remoteCtx.handle));
     238            0 :         HCCL_INFO(
     239              :             "[JettyContext][%s] unimport shared remote jetty, handle[%llu].", __func__,
     240              :             static_cast<unsigned long long>(remoteCtx.handle));
     241            0 :         remoteCtx.handle = 0;
     242            0 :         remoteCtx.handlePtr = nullptr;
     243            0 :         remoteCtx.ready = false;
     244              :     }
     245              : }
     246              : 
     247            5 : void JettyContext::DestroyJettyResources(Inner& inner)
     248              : {
     249            5 :     if (inner.handle != 0) {
     250            1 :         Hccl::HrtRaUbDestroyJetty(inner.handle);
     251            1 :         HCCL_INFO(
     252              :             "[JettyContext][%s] destroyed shared jetty, handle[%llu].", __func__,
     253              :             static_cast<unsigned long long>(inner.handle));
     254              :     }
     255            5 :     if (inner.jfcHandle != 0 && inner.rdmaHandle != nullptr) {
     256            1 :         Hccl::HrtRaUbDestroyJfc(static_cast<Hccl::RdmaHandle>(inner.rdmaHandle), inner.jfcHandle);
     257            1 :         HCCL_INFO(
     258              :             "[JettyContext][%s] destroyed shared jfc, jfcHandle[%llu].", __func__,
     259              :             static_cast<unsigned long long>(inner.jfcHandle));
     260              :     }
     261            5 :     if (inner.sqPiPtr != nullptr) {
     262            5 :         (void)hrtFree(inner.sqPiPtr);
     263            5 :         inner.sqPiPtr = nullptr;
     264              :     }
     265            5 :     if (inner.sqCiPtr != nullptr) {
     266            5 :         (void)hrtFree(inner.sqCiPtr);
     267            5 :         inner.sqCiPtr = nullptr;
     268              :     }
     269            5 :     if (inner.cqPiPtr != nullptr) {
     270            5 :         (void)hrtFree(inner.cqPiPtr);
     271            5 :         inner.cqPiPtr = nullptr;
     272              :     }
     273            5 :     if (inner.cqCiPtr != nullptr) {
     274            5 :         (void)hrtFree(inner.cqCiPtr);
     275            5 :         inner.cqCiPtr = nullptr;
     276              :     }
     277              :     // 防御性清空:销毁完成后句柄类字段不再有效,避免后续误用悬挂句柄
     278              :     // (Release 路径随后会 inner_ = Inner{},此处清空主要保护 memcpy_s 失败分支等提前销毁场景)
     279            5 :     inner.handle = 0;
     280            5 :     inner.jfcHandle = 0;
     281            5 :     inner.rdmaHandle = nullptr;
     282            5 : }
     283              : 
     284           25 : JettyContext::Ctx JettyContext::InnerToCtx(const Inner& inner)
     285              : {
     286           25 :     Ctx ctx{};
     287           25 :     ctx.handle = inner.handle;
     288           25 :     ctx.handlePtr = inner.handlePtr;
     289           25 :     ctx.jettyId = inner.jettyId;
     290           25 :     ctx.sqBuffVa = inner.sqBuffVa;
     291           25 :     ctx.dbAddr = inner.dbAddr;
     292           25 :     ctx.keySize = inner.keySize;
     293           25 :     ctx.sqDepth = inner.sqDepth;
     294           25 :     ctx.sqPiPtr = inner.sqPiPtr;
     295           25 :     ctx.sqCiPtr = inner.sqCiPtr;
     296           25 :     ctx.cqPiPtr = inner.cqPiPtr;
     297           25 :     ctx.cqCiPtr = inner.cqCiPtr;
     298           25 :     ctx.queueIndexMemSize = inner.queueIndexMemSize;
     299           25 :     ctx.rdmaHandle = inner.rdmaHandle;
     300           25 :     ctx.jfcHandle = inner.jfcHandle;
     301           25 :     ctx.cqInfo = inner.cqInfo;
     302           25 :     ctx.localPsn = inner.localPsn;
     303           25 :     if (inner.keySize > 0 && inner.keySize <= Hccl::HRT_UB_QP_KEY_MAX_LEN) {
     304           19 :         (void)memcpy_s(ctx.localQpKey, Hccl::HRT_UB_QP_KEY_MAX_LEN, inner.localQpKey, inner.keySize);
     305              :     }
     306           25 :     return ctx;
     307              : }
     308              : 
     309              : } // namespace hcomm
        

Generated by: LCOV version 2.0-1