HmgNextOwned doesn't do, by itself, all that much. There is some mild pointer-chasing, but not too horrible. All it does is to go through the global GDI handle table and look for handles owned by the terminating process. It is used loosely as
DWORD index = 0;
while(true) {
SOME_GDI_OBJECT_TYPE obj;
index = HmgNextOwned(index, pid, &obj);
if(index == 0) break; // done / nothing found
// ... do some clean up of the object here
}
The thing is, this loop is executed 6 (12, if counting the instances inlined into NtGdiCloseProcess) times when terminating a process, for various object types, and for each call of HmgNextOwned it will lock and unlock the handle manager lock.