Windows 95 System Programming Secrents Learning Notes - Chapter 3 (6)

xiaoxiao2021-03-06  39

Thread control function

Win32 API provides several functions to modify and query the execution status of the thread. At the bottom layer, the thread can read some of the registers of another thread (assuming it has other threads of HANDLE). In terms of high-level, some Win32 API allows you to suspend / start other threads. Let's take a look at these thread control functions.

GetThreadContext and IgetthreadContext

GetThreadContext makes the thread have the ability to get a copy of the register of another thread. At any time, the thread is either executed, or it is for the suspend state. Even if the thread is suspended, its register value is saved in a structure called Thread Context. The GetThreadContext function allows you to read the Thread Context that hangs hangs.

The GetThreadContext function is actually just the inspection of the parameters. It checks whether the incoming pointer points to the memory block sufficient to accommodate the Context structure. If the answer is affirmative, the program code jumps to the internal function IgetthreadContext.

IGetThreadContext first converts the hthread parameter as a Thread Database pointer, then calls x_threadcontext_copyregs, and store the input register group to the RING3's Context structure. In addition to copying register content to Ring3 CONTEXT structure, IgetthReadContext also calls vwin32.vxd to get RING0 version of those registers. As for the registers why there are Ring0 and Ring3, it is not very clear.

After filled the Context structure, GetThreadContext checks the value of the CS and the flag register to see if it is legal. The check register is very simple, just determines that it is currently not from V86 mode.

X_ThreadContext_copyregs

This function copies the selected register content from a Context structure to another CONTEXT structure. The Context structure is defined with Winnt.h.

supplement:

In the Winnt.h of the SDK comes with the Visual Studio.Net 2003, the Context structure definitions for AMD, Alpha, X86, MIPS, PPC (Power PC), and IA64 Six CPUs, respectively, respectively. In the Context structure for the x86, the first member is DWORD contextflags, which is used to indicate those registers in Contexts should be copied. The possible values ​​of ContextFlags are as follows:

CONTEXT_EXTENDED_REGISTERS // CPU Specific Extensions

Context_debug_registers // Debug Register 0-3, 6, 7

Context_floating_point / / The state of the arithmetic coprocessor 387

Context_segments // DS, ES, FS, GS

Context_integer // AX, BX, CX, DX, Si, Di

Context_Control // SS: SP, CS: IP, Flags, BP

The x_threadcontext_copyregs function is very straightforward. It faithfully checks the ContextFlags flag of the source (for x86), according to its instructions to copy the corresponding register value to the Context of the destination. There is no surprising discovery in the program code.

SetthreadContext and ISETTHREADCONTEXT

SetThreadContext enables threads to change the registers of another thread. This function is complementary to GetThreadContext.

Suspendthread and vwin32_suspendthread

SuspendThread will affect the number of threads. If the number of hangs is not 0, the Ring0 thread scheduler must never perform the thread. SuspendThread function code is actually just that I am so-called vwin32_suspendthread internal function outside the package. Vwin32_suspendthread waits for a Thread Database pointer, so SuspendThread first converts HThread to a useful pointer before calling it. If VMWIN32_SUSPENDTHREAD is successful, SuspendThread increases the number of hangs in Thread Database 1BCH. However, it is important that when the thread meter determines which thread can be implemented, the number of suspendments is not a determinant. In pair, VWIN32 saves the real number of hangs in the TDBX structure. Vwin32_suspendthread is actually only an outer packaging of the underlying function, which calls vwin32.vxd through an unprecedented vxdcall function.

ResMethread

This function is complementary to ResumeThread. It will reduce the suspend state of a thread (whether in the TBDX structure of Ring0, or in the thread Database 1BCH position of Ring3). When the suspend state will be 0, the thread is eligible to be considered a possible execution object by the scheduler.

ResumeThread first converts the HTHREAD parameter into a Thread Database pointer, then check the number of hangs of RING3, determined not 0 (if it is 0, the resumethread does not do anything). Next, call a Vwin32.vxd service function, minus the number of hangs 1. If the service function of vwin32.vxd can successfully reduce the number of hanging times of RING0, then ResumeTHread minus the number of hanging times of RING3.

Structured exception handling (Structured Execption Handling)

Structured exception handling, referred to as SEH) in modern operating systems, such as OS / 2, Windows NT, Windows9x, etc., is a topic that is promoted and often misunderstood. Most of them talk about his books and articles all put it on the compiler level. The compiler uses some reserved words such as: __ try, __ eXce, __ finally, catch, throw, package the messy operating system base interface.

When an exception (for example, Page Fault) occurs, the CPU will immediately transfer control to Ring0 exception handler, the latter's address stores in an Interrupt Descriptor Table. The RING0 processing function can determine how it is good. If this is a system knows how to deal with an exception, Ring0 code makes the necessary measures, and then let the instruction continue. These abnormalities are basically invisible to Ring3 code and System DLLS, and we don't care about them.

What we care about here is that if the system does not know how to handle this exception. How to do? The typical response of the old operating system is to cut off the process that caused abnormal conditions. Although the philosophy of "End of any procedures caused by unpredictable errors" is impeccable, it has no inclusiveness after all. A better approach is to let them depends on how to deal with the app (or other application).

32-bit OS, such as OS / 2 and NT introduced a more resilient processing method - structured abnormal treatment (SEH). In terms of processing multithreading and using C Catch / Throw mechanism, SHE is much better than before. For C abnormal conditions, the application itself can trigger an abnormal abnormality in one and CPU abnormal conditions. Assuming that the C New operator fails, it will throw an abnormal situation indicating insufficient memory. The SHE mechanism of the 32-bit operating system has sufficient elasticity, with the same code, and handles the abnormality of the language and the exception of hardware. Before moving forward, I would like to emphasize that I want to talk about the operation of SHE at the operating system level.

In a system with SHE, each thread has its own SEH chain contains set exception handle functions. When an exception occurs, the operating system visits the SEH chain and calls the appropriate exception handler. Such actions have continued until an exception function is transmitted back, indicating that it is to handle this abnormal position. This is the first stage: find the prostitute. If these functions can handle this exception, the system will come out and cut off the process of trouble. We don't care about the following circumstances, because the operating system cuts the process is very simple.

When you get a function to deal with an exception, the second phase is to re-visiting the She chain over again. Unapproved function RTLUNWIND functions do this for us, it is called by the "decision to handle this exception situation". When RTLunwind triggers the function of those SEH chains, the system will give them a sign. This logo tells the function that the stack of thread is currently being "unwound". The stack "unwinding" is a way to "restore the status status to the state of the exception handler". Not only re-resumed in the __except block, the system will also give yourself with each "installed, but do not process this exception". After giving this opportunity, important things such as "The destructive function of the C object in the stack" can be done in a discipline.

Translation:

The so-called "unwind" is that the objects in the stack are destructed when an exception occurs. This is the standard requirements of ANSI. As far as I know, OWL supports complete "stack unwinding", and early MFC does not contain automatic Stack unwinding. How does the new version of MFC performance are unknown.

There are enough theories, what is the structure and method of Windows 95 really used? When I introduced Tib, I said, fs: [0] is always this link to the current thread's SEH chain, the chain of exception handle functions is an ExceptionRegistrationRecord Link list. This long name comes from the BSExcept.h documentation of OS2 / 2.0. For some reasons, Microsoft seems to have an attempt to hide the usual information of SEH at the operating system level. The ExceptionRegistrationRecored structure looks like this:

DWord prev_structure // a Pointer to the Previously

// Installed ExceptionRegistrationRecored

DWord ExceptionHandler // Address of the Exception Handler Function

The finals of the linked list are ended in -1 (prev_structure).

Under normal circumstances, the program will use the space from the stack to create ExceptionRegistrationRecord. In the C / C program, each ExceptionRegistrationRecord corresponds to a __TRY / __EXCEPT block. When the program enters the __TRY block, the compiler produces a new ExceptionRegistrationRecord in the stack and puts it in the beginning of the SEH chain. After leaving the __except block, the compiler sets fs: [0] to the next ExceptionRegistrationRecord in the linked list. The figure below shows the data that are connected in series. Remember that the above 8-bit structure is only the minimum demand for the operating system. Nothing can prevent the compiler from producing a larger structure in the stack and put the ExceptionRegistrationRecord in the first place. The compiler can also provide sufficient information from other members obtained in the above structure to make a single exception handler for all __TRY blocks. Microsoft and Borland compilers use ExceptionRegistrationRecord's expansion structure.

Speaking of an exception handler, what is it like? Once again, Microsoft seems to hide certain information, but at least Win32 provides a function prototype. In EXCPT.H, you can see this prototype:

EXCEPTION_DISPSITION __CDECL _EXCEPT_HANDLER

Struct_exception_record * ExceptionRecord,

Void * EstablisherFrame,

Struct_Context * ContexTrecord,

Void * DispatcherContext

)

At first glance, it seems to be too complicated. Return Value Exception_Disposition is actually just an enum, telling the system how this function is used to handle exceptions:

Typedef enum _EXCEPTION_DISPSITION {

ExceptionContinueexecute,

ExceptionContinueSearch,

ExceptionnestedException,

ExceptionCollidedunwind

} EXCEPTION_DISPSITION;

The last two items will be encountered. As for the first ExceptionContinueexecute, it is to tell the system that the exception handler has handled the exception situation and intends to let the implementation continue. ExceptionContinuesearch is to tell the system that the exception handling routine does not intend to process this exception, the system should continue to visit the ExecEptionRegistrationRecord Link list until an exception handling routine returns ExceptionContinueexecute.

Rewind the _EXCEPT_HANDLER function prototype, it seems to be accepted:

INT _EXCEPT_HANDLER

PEXCEPTION_RECORD EXCEPTIONRECORD,

Pvoid ​​Establisherframe,

PCONText ContextRecord,

PVOID DispatcherContext);

We have found that an exception handler requires four pointer parameters, pointing to an abnormal condition, and a data structure such as machine status. This function returns an integer that tells the system whether it handles exceptions. EXCEPTION_RECORD structure contains exception code, as well as other things. Winnt.h is some instructions for this. The Context structure contains an abnormal register content, and Winnt.h has an explanation. The ESTABLISHERFRAME parameter contains a pointer, pointing to the setting of the stack --- ExceptionRegistrationRecord structure. The DispathcerContext parameter does not seem to be used. I said earlier, the exception handler will be called twice. The first time is the system to find a function of proper processing functions. The second time is for the system to "unwinding", and the processing function is considered necessary to make the necessary cleanup work (like the destructive function of the stack object, etc.). Where is the difference between these two calls? EXCEPTIONRECORD structure (referred to by the first parameter), if the EH_UNWINDDING (0x2) or EH_EXIT_UNWIND (0x4) flag is not set, then the first case; if the two flags are set up, then Is the second case.

supplement:

Regarding why the abnormal processing function is called twice, in detail in the book "32-bit assembler design under Windows", fundamentally, in order to clean up, restore the system status to an abnormality.

转载请注明原文地址:https://www.9cbs.com/read-70701.html

New Post(0)