ReactOS 图形系统分析(20):引擎信号量 — EngSemaphore(semaphor.c))
ReactOS 图形系统分析20引擎信号量 — EngSemaphoresemaphor.c1. 概述semaphor.c位于win32ss/gdi/eng/semaphor.c实现 GDI 引擎的同步原语族HSEMAPHORE——EngCreateSemaphore/EngAcquireSemaphore/EngReleaseSemaphore等一组 DDI 服务。它是引擎与显示驱动共享的互斥/共享锁接口。本质这里的信号量不是计数信号量而是ERESOURCE内核资源对象的轻量封装——支持排他写/共享读两种获取模式并天然支持递归持有同线程多次获取不自我死锁。配合**关键区Critical Region**使用保证锁持有期间普通内核 APC 不会打断避免锁被中断持有着替换。┌─────────────────────────────────────────────────────────────┐ │ 使用方 │ │ eng/device.c ghsemGraphicsDeviceList图形设备链表锁 │ │ eng/ldevobj.c ghsemLDEVList逻辑设备链表锁 │ │ eng/pdevobj.c ghsemPDEV ppdev-hsemDevLock每物理设备│ │ ntgdi/dclife.c / print.c / eng/mouse.chsemDevLock 使用 │ │ reactx/dxg, ntddrawDirectX 全局句柄表锁 ghsemHmgr 等 │ ├─────────────────────────────────────────────────────────────┤ │ gdi/eng/semaphor.c本分析对象 │ │ HSEMAPHORE PERESOURCEERESOURCE*不透明句柄 │ │ ├── EngCreateSemaphore / EngDeleteSemaphore │ │ ├── EngAcquireSemaphore排他/ AcquireSemaphoreShared共享│ │ ├── EngReleaseSemaphore │ │ ├── EngIsSemaphoreOwned / OwnedByCurrentThread │ │ └── EngInitializeSafeSemaphore / DeleteSafeSemaphore │ │ ENGSAFESEMAPHORE延迟初始化 引用计数的安全封装 │ ├─────────────────────────────────────────────────────────────┤ │ 底层ntoskrnl ERESOURCEExInitializeResourceLite 等 │ │ ExEnterCriticalRegion / KeEnterCriticalRegion │ └─────────────────────────────────────────────────────────────┘2. 核心函数实现2.1 EngCreateSemaphore — 创建分配 初始化 ERESOURCEHSEMAPHOREEngCreateSemaphore(VOID){PERESOURCE psemExAllocatePoolWithTag(NonPagedPool,sizeof(ERESOURCE),GDITAG_SEMAPHORE);// 非分页池if(!psem)returnNULL;if(!NT_SUCCESS(ExInitializeResourceLite(psem))){// 初始化资源ExFreePoolWithTag(psem,GDITAG_SEMAPHORE);returnNULL;}return(HSEMAPHORE)psem;// 句柄 资源指针}关键点分配于NonPagedPool锁代码路径不允许分页缺页HSEMAPHORE实际就是ERESOURCE*只是对外不透明。EngDeleteSemaphore逆操作ExDeleteResourceLite 释放池。2.2 获取 / 释放VOIDEngAcquireSemaphore(HSEMAPHORE hsem)// 排他写锁{if(hsemNULL)return;// Windows 语义NULL 忽略ExEnterCriticalRegionAndAcquireResourceExclusive((PERESOURCE)hsem);W32ThreadPsGetThreadWin32Thread(PsGetCurrentThread());if(W32Thread)W32Thread-dwEngAcquireCount;// 引擎锁嵌套计数统计}VOIDEngAcquireSemaphoreShared(HSEMAPHORE hsem)// 共享读锁{ExEnterCriticalRegionAndAcquireResourceShared((PERESOURCE)hsem);if(pti)pti-dwEngAcquireCount;}VOIDEngReleaseSemaphore(HSEMAPHORE hsem){if(hsemNULL)return;if(W32Thread)--W32Thread-dwEngAcquireCount;ExReleaseResourceAndLeaveCriticalRegion((PERESOURCE)hsem);}设计要点Critical RegionExEnterCriticalRegion.../...AndLeaveCriticalRegion把进入关键区和获取/释放资源合成一步。关键区内普通 APC 被屏蔽保证线程持锁期间状态不被异步打断。递归安全ERESOURCE 允许同线程递归获取每次 Release 减递归计数引擎多处嵌套持有同一把hsemDevLock依赖此特性。共享模式EngAcquireSemaphoreShared让多个读者并发进入设备表面属性读取场景写者互斥——类似读写锁。dwEngAcquireCount[win32.h](file:///d:/reactos/win32ss/user/ntuser/win32.h#L68) 中 THREADINFO 字段跟踪当前线程持有引擎锁的嵌套深度为未来的死锁/锁泄漏诊断预留当前仅计数、未消费。2.3 查询函数函数实现语义EngIsSemaphoreOwnedActiveCount 0是否被任意线程持有EngIsSemaphoreOwnedByCurrentThreadExIsResourceAcquiredExclusiveLite当前线程是否持有排他锁递归检测用2.4 ENGSAFESEMAPHORE — 安全信号量[winddi.h](file:///d:/reactos/sdk/include/psdk/winddi.h#L559-L562)typedefstruct_ENGSAFESEMAPHORE{HSEMAPHORE hsem;LONG lCount;// 引用计数初次使用线程数}ENGSAFESEMAPHORE;BOOLEngInitializeSafeSemaphore(ENGSAFESEMAPHORE*Semaphore){if(InterlockedIncrement(Semaphore-lCount)1)// 第一个使用者{hSemEngCreateSemaphore();// 才真正创建if(hSem0){InterlockedDecrement(...);returnFALSE;}InterlockedExchangePointer(Semaphore-hsem,hSem);// 发布}else{/* 其他线程等待创建者完成初始化 */while(Semaphore-hsemNULL);// 忙等}returnTRUE;}用途驱动结构体里内嵌的可能同时被多线程首次访问的延迟初始化锁——第一次使用时创建后续使用只增加引用计数。EngDeleteSafeSemaphore对称地InterlockedDecrement归零才删除。已知缺陷源码 FIXME 标注用InterlockedExchangePointer而非InterlockedCompareExchangePointer——若两线程同时首次进入可能创建两个ERESOURCE后写的覆盖先写的泄漏一个。正确写法应 CAS 校验后释放失败者。这是 ReactOS 明确记录的待修复点。3. 使用场景与全局锁清单全局/每对象锁创建位置保护对象ghsemGraphicsDeviceList[device.c](file:///d:/reactos/win32ss/gdi/eng/device.c#L28)图形设备链表EngpRegisterGraphicsDevice 增删/枚举ghsemLDEVList[ldevobj.c](file:///d:/reactos/win32ss/gdi/eng/ldevobj.c#L38)逻辑设备LDEVOBJ链表ghsemPDEV[pdevobj.c](file:///d:/reactos/win32ss/gdi/eng/pdevobj.c#L33)物理设备PDEV全局状态ppdev-hsemDevLock[pdevobj.c](file:///d:/reactos/win32ss/gdi/eng/pdevobj.c#L73)单个物理设备模式切换、表面、DC 关联最常用ghsemShareDevLock[ntddraw/dxeng.c](file:///d:/reactos/win32ss/reactx/ntddraw/dxeng.c#L182)DirectDraw 共享设备锁ghsemHmgr[dxg/ddhmg.c](file:///d:/reactos/win32ss/reactx/dxg/ddhmg.c#L57)DirectX 全局句柄管理器典型调用链设备锁NtGdiXXX (操作设备表面) ↓ ntgdi/dclife.c / print.c / eng/mouse.c ↓ EngAcquireSemaphore(ppdev-hsemDevLock) 访问/修改 PDEV 状态模式、表面关联、指针 ↓ EngReleaseSemaphore(ppdev-hsemDevLock)4. 导出与消费路径4.1 win32k.spec 导出[win32k.spec](file:///d:/reactos/win32ss/win32k.spec) stdcall EngAcquireSemaphore(ptr) # L8 stdcall EngCreateSemaphore() # L30 stdcall EngDeleteSafeSemaphore(ptr) # L40 stdcall EngDeleteSemaphore(ptr) # L41 stdcall EngInitializeSafeSemaphore(ptr) # L79 stdcall EngIsSemaphoreOwned(ptr) # L80 stdcall EngIsSemaphoreOwnedByCurrentThread(ptr) # L81 stdcall EngReleaseSemaphore(ptr) # L115注EngAcquireSemaphoreShared未导出——仅供引擎内部使用声明在 [eng.h](file:///d:/reactos/win32ss/gdi/eng/eng.h#L10-L17)。4.2 DXGTHK 重新导出用户态 DirectX 驱动[dxgthk.spec](file:///d:/reactos/win32ss/reactx/dxgthk/dxgthk.spec) 把EngAcquireSemaphore/EngCreateSemaphore/EngReleaseSemaphore/EngDeleteSemaphore从 win32k.sys重新导出到 dxgthk.dll——用户态 DirectX 驱动如显示驱动 thunk可通过 dxgthk 调用内核锁。5. 与《分析_4》标注对照标注核对《_4》第 40 行semaphor.c 「信号量EngAcquireSemaphore」准确。补充完整 8 个函数族基于 ERESOURCE 的排他/共享资源锁而非计数信号量EngAcquireSemaphoreShared仅供内部6. 源码索引文件关键内容[semaphor.c](file:///d:/reactos/win32ss/gdi/eng/semaphor.c)EngCreate/Delete/Acquire/Release/IsOwned/IsOwnedByCurrentThread、AcquireSemaphoreShared、SafeSemaphore 初始化/删除[eng.h](file:///d:/reactos/win32ss/gdi/eng/eng.h#L10-L17)EngAcquireSemaphoreShared 内部声明[winddi.h](file:///d:/reactos/sdk/include/psdk/winddi.h#L559-L562)ENGSAFESEMAPHORE 结构[device.c](file:///d:/reactos/win32ss/gdi/eng/device.c#L28)ghsemGraphicsDeviceList[ldevobj.c](file:///d:/reactos/win32ss/gdi/eng/ldevobj.c#L38)ghsemLDEVList[pdevobj.c](file:///d:/reactos/win32ss/gdi/eng/pdevobj.c#L33-L95)ghsemPDEV、ppdev-hsemDevLock 创建/删除[win32.h](file:///d:/reactos/win32ss/user/ntuser/win32.h#L68)THREADINFO.dwEngAcquireCount[dxgthk.spec](file:///d:/reactos/win32ss/reactx/dxgthk/dxgthk.spec)向用户态重新导出 Eng* 信号量关联模块底层机制ntoskrnl ERESOURCE / Critical Region主要使用者[eng/device.c](file:///d:/reactos/win32ss/gdi/eng/device.c)、[eng/ldevobj.c](file:///d:/reactos/win32ss/gdi/eng/ldevobj.c)、[eng/pdevobj.c](file:///d:/reactos/win32ss/gdi/eng/pdevobj.c)、[reactx/](file:///d:/reactos/win32ss/reactx/)锁保护对象图形设备链表 / LDEV / PDEV见《分析_4》2.3 节设备对象体系本文档基于 ReactOS 源代码win32ss/gdi/eng/semaphor.c及关联模块分析2026 年 8 月