Call_Restricted_Event


include vmm.inc

mov     eax, PriorityBoost
mov     ebx, Handle
mov     ecx, Flags
mov     edx, RefData
mov     esi, OFFSET32 RestrictedProc
mov     edi, Timeout
VMMcall Call_Restricted_Event
mov     [EventHandle], esi

Combines the functionality of the Call_VM_Event, Call_When_VM_Ints_Enabled, Call_When_Not_Critical, and Adjust_Exec_Priority services into one service.

The service allows a VxD to specify flags which place restrictions on when the VMM can call the event callback function. Restrictions include such things as the event callback function can be called only when interrupts are enabled, only when the critical section is unowned, and so on.

As with all event services, this service can be called from an interrupt handler. This is an asynchronous service. Uses ESI and Flags.

PriorityBoost

Priority boost for the virtual machine. This parameter must be a value such that when added to the current execution priority, the result is within the range Reserved_Low_Boost to Reserved_High_Boost. This parameter can be 0 if no boost is necessary. Common priority boost values, from lowest to highest, are as follows:

Value

Meaning

Reserved_Low_Boost

Reserved for use by system.

Low_Pri_Device_Boost

Use for operations that need timely processing but are not time critical.

High_Pri_Device_Boost

Use for time-critical operations that should not circumvent the critical section boost.

Critical_Section_Boost

Use to boost the priority of the virtual machine whenever it enters a critical section (calls Begin_Critical_Section).

Time_Critical_Boost

Use for operations that require immediate processing, even when another virtual machine is in a critical section. For example, VPICD uses this when simulating hardware interrupts.

Reserved_High_Boost

Reserved for use by system.


For global events, the priority boost only goes into effect after restrictions have been met; that is, just before the VMM calls the event callback function. For VM events, the priority boost is originally applied to the whole VM, but will be moved to the thread that the event is called on unless Flags specifies the PEF_Dont_Unboost flag.

Forgetting to pass a priority value in the EAX register is a common error.

Handle

If the PEF_Thread_Event flag is specified, this parameter contains the handle of the thread for which the event callback is requested; Otherwise, the value of this parameter is zero when the event is a global event or the handle of the virtual machine for which the VM event callback is requested.

Flags

A combination of these action flags:

Value

Meaning

PEF_Always_Sched

Event is always scheduled, meaning the callback function is never called immediately.

PEF_Dont_Unboost

Priority of the virtual machine or thread is not reduced after return from callback function.

PEF_Thread_Event

Handle is the handle of the thread for which the event is requested. The callback function is called only in the context of the thread.

PEF_Time_Out

The time-out value in the EDI register should be used. Available in Windows version 3.1 or later.

PEF_Wait_For_STI

Callback function is not called until the virtual machine enables interrupts in all threads.

PEF_Wait_Not_HW_Int

Callback function is not called while the VPICD is simulating a hardware interrupt.

PEF_Wait_In_PM

Callback function is not called until the virtual machine or thread is executing in protected mode. Use this flag with caution — it may never happen for VM other than the system VM unless an MS-DOS Protected Mode Interface (DPMI) application is running.

PEF_Wait_Not_Crit

Callback function is not called until the virtual machine is not in a critical section or time-critical operation. See remarks below.

PEF_Wait_Not_Nested_Exec

Callback function is not called while the virtual machine is in a nested execution block.

PEF_Wait_For_Thread_STI

Callback function is not called until interrupts are enabled at ring 3 in the current thead.

PEF_Ring0_Event

Callback function completes at ring 0. See remarks below.

PEF_Wait_Crit

Callback function is not called until (1) the critical section is free, or (2) the critical section is owned by the current thread. See remarks below.

PEF_Wait_Crit_VM

Callback function is called when critical section not owned by other thread in VM. See remarks below.

PEF_Process_Last

See description below.


All other values are reserved.

RefData

Reference data to pass to the callback function.

EventCallback

Address of the callback function to install. For more information about the callback function, see RestrictedEventCallback.

TimeOut

Number of milliseconds until the event times out. The service uses this parameter only if the PEF_Time_Out value is specified by Flags.

If a timeout occurs before the restrictions are met, the event callback will be called with carry set.

A VxD uses the Call_Restricted_Event service for purposes that include the following:

Global restricted events can happen in any VM that meets the restriction. VM-restricted events can only happen in the specified VM; and now that multiple threads are supported in the system VM, restricted thread events can be specified to only happen in the one thread context (although specifying that interrupts must be enabled for a thread event will only happen when interrupts are enabled in all threads of that VM.)

The PEF_Wait_Not_Crit flag will delay the processing of the event until the critical section is free and the priority of the current thread or virtual machine is less than Critical_Section_Boost. One should be careful not to pass too large a PriorityBoost when this flag is set. (In particular, passing a PriorityBoost greater than or equal to Critical_Section_Boost will prevent the event from ever satisfying its own restrictions.)

The PEF_Wait_For_Thread_STI flag differs from the PEF_Wait_For_STI flag in that the former checks the status of only the current thread, whereas the latter checks the status of all threads in the virtual machine. The two flags may not be combined.

The PEF_Ring0_Event flag indicates that the event can complete entirely at ring 0 without faulting. The requirements for 'ring 0' events are very strict, and apply to the event callback procedure and anything it calls, directly or indirectly. Although some rules in the system are relaxed if 32-bit disk access is enabled, these rules remain in full force. Ring 0 events must restrict memory accesses to locked code and locked data. They must not call Begin_Nest_Exec, Resume_Exec, Exec_VxD_Int, Exec_Int, or any service or procedure that in turn calls one of those services. They must not block on any synchronization objects. They must not adjust any thread's execution priority. In brief, they must guarantee that they will carry out their work to completion without running any code at ring 3, and without causing a task switch. In exchange for these guarantees, ring 0 events can be processed even if a thread has specifically requested that events not be processed. Ring 0 events are very dangerous. It is strongly recommended that they be avoided entirely. The flag is listed here for completeness.

The PEF_Wait_Crit flag indicates that the event may be processed only if the current thread owns the critical section, or if the critical section is unowned. This restriction may be applied only to global events (Handle = 0). The event callback can then be assured that it can call Begin_Critical_Section without blocking. PEF_Wait_Crit events allow you to ensure that a section of code be executed as soon as possible under the protection of the critical scetion. In Windows 3.1, this was done by a chain of events which repeatedly determine the critical section owner, then either perform the requested action or reschedule the same event for the current critical section owner and trying again. Since the ownership of the critical section can change between the time the event is scheduled and the time the event is processed, this chain of events may continue for several iterations before finally completing. (If you draw a picture, you can see why this is informally known as 'chasing the critical section'.) Starting with Windows 95, the PEF_Wait_Crit flag is the recommended way of accomplishing this.

The PEF_Wait_Crit_VM flag may be set only if Handle is equal to the System VM handle. It indicates that the event may be processed when the current thread is a thread in the System VM, and one of the following conditions is also met: (1) The critical section is unowned. (2) The critical section is owned by the current thread. (3) The critical section is owned by a thread not in the System VM. Writers of virtual device drivers should not normally have need for this flag. It is documented here for completeness.

The PEF_Process_Last allows a limited degree of control over the order in which events are processed. Normally, global events are processed first, then VM events, then thread events. This flag causes the event to be removed from consideration during the initial check for processable events. If the initial check fails to find any events, then a second pass is made during which this event can be selected. The only time this flag should be set is on a VM event (Handle is a valid VM handle), to indicate that the current thread should have no thread events when the VM event is processed. It does not add the event to the end of a list. Writers of virtual device drivers should not normally have need for this flag. It is documented here for completeness.

See also Adjust_Exec_Priority, Begin_Critical_Section, Call_VM_Event, Call_When_Not_Critical, Call_When_VM_Ints_Enabled, Cancel_Restricted_Event, RestrictedEventCallback