Connection Server 代码详细分析
文件概述
文件名: connection_server.c
功能: 服务器端连接管理,处理来自客户端的连接请求和基于连接的信息管理
核心数据结构
CONNECTION_DATA 结构
CONNECTION_DATA {
- pid: 进程ID
- vpid: 虚拟进程ID
- tid: 线程ID
- pszProcName: 进程名称
- psHandleBase: 连接句柄基础
- psProcessHandleBase: 进程句柄基础
- psSyncConnectionData: 同步连接数据
- psPDumpConnectionData: PDump连接数据
- hOsPrivateData: OS私有数据
- hProcessStats: 进程统计信息
- hClientTLStream: 客户端TL流
- ui32ClientFlags: 客户端标志
- sConnectionListNode: 连接链表节点
- sCleanupThreadFn: 清理线程函数
}
关键常量定义
#define CONNECTION_CLEANUP_RETRY_TIMEOUT_MS (MAX_HW_TIME_US / 1000 * 240)
- 作用: 设置清理线程销毁连接资源的最大重试时间
- 计算: 基于 MAX_HW_TIME_US (通常500-1000ms),结果为2-4分钟
核心函数详细分析
PVRSRVCommonConnectionConnect()
功能: 建立客户端到服务器的连接
流程图
代码流程
- 内存分配
psConnection = OSAllocZMemNoStats(sizeof(*psConnection));- 使用无统计的分配方式(因为进程尚未注册)
- 进程统计注册
#if defined(PVRSRV_ENABLE_PROCESS_STATS) PVRSRVStatsRegisterProcess(&psConnection->hProcessStats); #endif - OS层初始化
OSConnectionPrivateDataInit(&psConnection->hOsPrivateData, pvOSData); - 设备状态检查
if (psDevNode->eDevState == PVRSRV_DEVICE_STATE_DEINIT || psDevNode->eDevState == PVRSRV_DEVICE_STATE_DESTRUCTING) - 进程信息记录
psConnection->pid = OSGetCurrentClientProcessIDKM(); psConnection->vpid = OSGetCurrentVirtualProcessID(); psConnection->tid = OSGetCurrentClientThreadIDKM(); OSStringSafeCopy(psConnection->pszProcName, ...); - DMA支持初始化 (可选)
#if defined(SUPPORT_DMA_TRANSFER) - 创建DMA请求锁 - 创建DMA事件对象 - 初始化DMA子系统 - 增加引用计数 #endif - 同步系统注册
SyncRegisterConnection(&psConnection->psSyncConnectionData); - PDump注册
PDumpRegisterConnection(psDevNode, psConnection->psSyncConnectionData, SyncConnectionPDumpSyncBlocks, &psConnection->psPDumpConnectionData); - 句柄分配
PVRSRVAllocHandleBase(&psConnection->psHandleBase, PVRSRV_HANDLE_BASE_TYPE_CONNECTION); PVRSRVAcquireProcessHandleBase(&psProcessHandleBase); - 加入设备连接列表
OSLockAcquire(psDevNode->hConnectionsLock); dllist_add_to_tail(&psDevNode->sConnections, &psConnection->sConnectionListNode); OSLockRelease(psDevNode->hConnectionsLock);
ConnectionDataDestroy()
功能: 销毁连接数据并释放所有关联资源
流程图
重要特性
- 重试机制
- 如果资源正被固件使用,返回
PVRSRV_ERROR_RETRY - 允许进行中的工作完成后再进行清理
- 如果资源正被固件使用,返回
- 资源释放顺序
HWPerf流 → 句柄基础 → 同步数据 → PDump数据 → 设备统计 → OS数据 → 进程统计 → 内存 - 时间控制
if (psPVRSRVData->bUnload) ui64MaxBridgeTime = 0; // 驱动卸载时不允许释放桥锁 else ui64MaxBridgeTime = CONNECTION_DEFERRED_CLEANUP_TIMESLICE_NS;
PVRSRVCommonConnectionDisconnect()
功能: 断开客户端连接
流程图
DMA清理机制
#if defined(SUPPORT_DMA_TRANSFER)
1. 设置 bAcceptDmaRequests = IMG_FALSE
2. WaitForOutstandingDma() - 等待进行中的传输
3. 减少引用计数
4. 如果引用计数为0,反初始化DMA
5. 销毁事件对象和锁
#endif
延迟清理配置
psConnectionData->sCleanupThreadFn.pfnFree = _CleanupThreadPurgeConnectionData;
psConnectionData->sCleanupThreadFn.pvData = psConnectionData;
psConnectionData->sCleanupThreadFn.bDependsOnHW = IMG_TRUE;
psConnectionData->sCleanupThreadFn.eCleanupType = PVRSRV_CLEANUP_TYPE_CONNECTION;
CLEANUP_THREAD_SET_RETRY_TIMEOUT(&psConnectionData->sCleanupThreadFn,
CONNECTION_CLEANUP_RETRY_TIMEOUT_MS);
WaitForOutstandingDma()
功能: 等待所有未完成的DMA传输完成
实现细节
static void WaitForOutstandingDma(CONNECTION_DATA *psConnectionData)
{
IMG_UINT32 ui32Tries = 100; // 最多等待5秒 (100 * 50ms)
while (OSAtomicRead(&psConnectionData->ui32NumDmaTransfersInFlight) != 0)
{
OSSleepms(50); // 每次睡眠50ms
if (!ui32Tries)
{
// 超时处理
PVR_DPF((PVR_DBG_ERROR, "Timeout waiting on DMA transfers!"));
break;
}
ui32Tries--;
}
}
_CleanupThreadPurgeConnectionData()
功能: 清理线程中执行的连接数据清除
流程
static PVRSRV_ERROR _CleanupThreadPurgeConnectionData(void *pvConnectionData)
{
1. 记录当前清除的连接PID
gCurrentPurgeConnectionPid = psConnectionData->pid;
2. 销毁连接数据
eErrorConnection = ConnectionDataDestroy(psConnectionData);
3. 检查全局句柄基础是否需要调整大小
eErrorKernel = PVRSRVPurgeHandles(KERNEL_HANDLE_BASE);
4. 清除当前PID记录
gCurrentPurgeConnectionPid = 0;
5. 返回结果
}
PVRSRVConnectionDebugNotify()
功能: 输出连接调试信息
输出格式
Connections Device ID:X(Y) P<pid>-V<vpid>-T<tid>-<process_name>, ...
特性
- 批量显示: 将多个连接信息组合在一行
- 智能换行: 当剩余空间不足时自动换行
- 缩进保持: 后续行保持相同缩进
- 线程安全: 使用
hConnectionsLock保护
系统架构图
连接生命周期
关键机制说明
句柄管理
两级句柄系统:
1. 连接句柄基础 (psHandleBase)
- 类型: PVRSRV_HANDLE_BASE_TYPE_CONNECTION
- 生命周期: 绑定到单个连接
- 进程句柄基础 (
psProcessHandleBase)- 跨连接共享
- 引用计数管理
重试机制
触发条件:
- 固件正在处理工作负载
- 资源正被使用无法立即释放
实现:
if (PVRSRVIsRetryError(eError))
{
return eError; // 通知调用者重试
}
超时设置:
CONNECTION_CLEANUP_RETRY_TIMEOUT_MS = (MAX_HW_TIME_US / 1000 * 240)
// 通常为 2-4 分钟
DMA传输管理
引用计数机制:
if (psDevNode->ui32RefCountDMA == 0)
PVRSRVInitialiseDMA(psDevNode);
psDevNode->ui32RefCountDMA++;
// 断开时
if (--psDevNode->ui32RefCountDMA == 0)
PVRSRVDeInitialiseDMA(psDevNode);
传输跟踪:
OSAtomicWrite(&psConnection->ui32NumDmaTransfersInFlight, 0);
psConnection->bAcceptDmaRequests = IMG_TRUE;
同步与PDump
注册顺序:
1. 注册同步连接
2. 使用同步数据注册PDump
3. PDump回调: SyncConnectionPDumpSyncBlocks
HWPerf主机流
连接通知:
if (TLStreamIsOpenForReading(psRgxDevInfo->hHWPerfHostStream))
{
RGXSRV_HWPERF_HOST_CLIENT_INFO_PROCESS_NAME(
psDevNode,
psConnection->pid,
psConnection->pszProcName
);
}
错误处理策略
连接建立失败
failure:
ConnectionDataDestroy(psConnection);
return eError;
- 清理已分配的所有资源
- 返回错误码
断开连接失败
if (PVRSRVIsRetryError(eErrorConnection))
{
// 延迟销毁,稍后重试
}
- 加入清理线程队列
- 定期重试
DMA超时处理
if (!ui32Tries)
{
PVR_DPF((PVR_DBG_ERROR, "Timeout waiting on DMA!"));
break; // 强制继续,记录错误
}
线程安全
锁的使用
- 连接链表锁 (
hConnectionsLock)OSLockAcquire(psDevNode->hConnectionsLock); dllist_add_to_tail(&psDevNode->sConnections, ...); OSLockRelease(psDevNode->hConnectionsLock); - DMA请求锁 (
hDmaReqLock)OSLockAcquire(psConnectionData->hDmaReqLock); psConnectionData->bAcceptDmaRequests = IMG_FALSE; OSLockRelease(psConnectionData->hDmaReqLock); - HWPerf流锁 (
hLockHWPerfHostStream)OSLockAcquire(psRgxDevInfo->hLockHWPerfHostStream); bHostStreamIsNull = (psRgxDevInfo->hHWPerfHostStream == NULL); OSLockRelease(psRgxDevInfo->hLockHWPerfHostStream);
原子操作
OSAtomicWrite(&psConnection->ui32NumDmaTransfersInFlight, 0);
OSAtomicRead(&psConnectionData->ui32NumDmaTransfersInFlight);
性能考虑
内存分配策略
- 初期分配: 使用
OSAllocZMemNoStats(无统计开销) - 后期分配: 进程注册后使用正常分配
延迟清理
CONNECTION_DEFERRED_CLEANUP_TIMESLICE_NS
- 避免长时间持有桥锁
- 分时段清理资源
批量操作
- 调试输出时批量处理连接信息
- 减少锁的获取次数
调试支持
日志级别
PVR_DPF((PVR_DBG_MESSAGE, ...)); // 消息
PVR_DPF((PVR_DBG_ERROR, ...)); // 错误
PVR_DPF((PVR_DBG_DEBUG, ...)); // 调试
调试宏
#if defined(DEBUG) || defined(PDUMP)
PVR_LOG(("%s connected - (devID = %u)", ...));
#endif
连接信息转储
PVRSRVConnectionDebugNotify()
- 输出所有活动连接
- 包含进程ID、虚拟PID、线程ID和进程名
编译选项
| 宏定义 | 功能 |
|---|---|
PVRSRV_ENABLE_PROCESS_STATS |
启用进程统计 |
PVRSRV_DEBUG_LINUX_MEMORY_STATS |
Linux内存统计调试 |
SUPPORT_DMA_TRANSFER |
DMA传输支持 |
PVRSRV_ENABLE_GPU_MEMORY_INFO |
GPU内存信息 |
SUPPORT_PMR_DEFERRED_FREE |
PMR延迟释放 |
PVRSRV_FORCE_UNLOAD_IF_BAD_STATE |
强制卸载 |
DEBUG / PDUMP |
调试和PDump |
DMA_VERBOSE |
DMA详细日志 |
总结
核心职责
- 连接管理: 建立、维护、断开客户端连接
- 资源分配: 句柄、内存、子系统注册
- 生命周期管理: 优雅的资源清理和重试机制
- 调试支持: 完善的日志和信息转储
设计亮点
- 延迟清理机制: 避免阻塞主流程
- 重试策略: 处理固件繁忙情况
- 两级句柄系统: 连接级和进程级
- 线程安全: 完善的锁保护
- 错误恢复: 失败时完整清理
关键流程时序
Connect: 分配 → 初始化 → 注册 → 加入列表
Disconnect: 移除 → 通知 → 标记 → 延迟清理
Cleanup: 检查 → 销毁 → 重试 → 完成
性能特性
- 无锁原子操作
- 分时段资源释放
- 批量操作优化
- 最小化临界区
使用建议
- 连接建立: 确保检查返回值,处理失败情况
- 资源清理: 依赖延迟清理机制,不要同步等待
- DMA操作: 断开前确保所有传输完成
- 调试: 使用
PVRSRVConnectionDebugNotify查看活动连接 - 异常处理: 注意
PVRSRV_ERROR_RETRY的特殊含义
文档生成时间: 2025-10-30
基于源文件: connection_server.c
JINHU