Recently when I was debugging a dead locked program using WinDBG, I accidentally met with the following stack trace where I expected to see some API calls related to Critical section. Instead it had shown like ‘WaitForSingleObject
’ which is solely a kernel mode API. The thread was supposed to be wait state while other thread is owning the critical section shared among threads.
001bf994 77de9254 76fac244 00000080 00000000 ntdll!KiFastSystemCallRet
001bf998 76fac244 00000080 00000000 00000000 ntdll!ZwWaitForSingleObject+0xc
001bfa08 76fac1b2 00000080 ffffffff 00000000 kernel32!WaitForSingleObjectEx+0xbe
001bfa1c 009015ab 00000080 ffffffff 00000000 kernel32!WaitForSingleObject+0x12
001bfb04 00901e28 00000001 008679d8 00868b80 DeadLock!wmain+0x6b
[c:\users\sarath\documents\visual studio 2008\projects\deadlock\deadlock.cpp @ 21]
001bfb54 00901c6f 001bfb68 76fa4911 7ffd3000 DeadLock!__tmainCRTStartup+0x1a8
[f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c @ 579]
001bfb5c 76fa4911 7ffd3000 001bfba8 77dce4b6 DeadLock!wmainCRTStartup+0xf
[f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c @ 399]
001bfb68 77dce4b6 7ffd3000 7736d75f 00000000 kernel32!BaseThreadInitThunk+0xe
001bfba8 77dce489 00901096 7ffd3000 00000000 ntdll!__RtlUserThreadStart+0x23
001bfbc0 00000000 00901096 7ffd3000 00000000 ntdll!_RtlUserThreadStart+0x1b
Why can we see a kernel mode call here? Of course critical sections are faster than kernel mode synchronization objects, as it can avoid user mode to kernel mode transition. But the only condition is that, it shouldn’t have any conflicts in acquiring the resource. Critical sections are not purely user-mode synchronization objects. If a thread tries to acquire a critical section and if the object is owned by another thread, then it’s necessary to put the thread in wait mode. To make a thread into wait state, it’s necessary to have a transition from user mode to kernel mode. Of course the critical sections are fast, if there are no contentions. If a contention occurred, then it will be using kernel mode objects to make the corresponding thread in wait state.
Here’s a short note on user mode and kernel mode.
1. Kernel Mode
In Kernel mode, the executing code has complete and unrestricted access to the underlying hardware. It can execute any CPU instruction and reference any memory address. Kernel mode is generally reserved for the lowest-level, most trusted functions of the operating system. Crashes in kernel mode are catastrophic; they will halt the entire PC. Various drivers and operating system services are under kernel mode.
2. User Mode
In User mode, the executing code has no ability to directly access hardware or reference memory. Code running in user mode must delegate to system APIs to access hardware or memory. The, crashes in user mode are always recoverable as most of the system calls are executed via safe APIs. Most of the code running on your computer will execute in user mode.
Posted in C++, Code, CodeProject, Debugging, Misc, Tips Tagged: C++, Code, CodeProject, Debugging, Tips