ReacOS的源代码是从svn服务器下载,下载地址为:"svn://svn.reactos.org/reactos/trunk/reactos"(不包括双引号)。
源代码的根目录存放在ReactOS。SetEvent的函数路径为 ReactOS\dll\win32\kernel32\client\synch.c 。这个函数的作用是设置事件为有信号状态,使得其他线程可以获取该事件。
/*
* @implemented
*/
BOOL
WINAPI
DECLSPEC_HOTPATCH
SetEvent(IN HANDLE hEvent)
{
NTSTATUS Status;
/* Set the event */
Status = NtSetEvent(hEvent, NULL);
if (NT_SUCCESS(Status)) return TRUE;
/* If we got here, then we failed */
BaseSetLastNTError(Status);
return FALSE;
}
SetEvent函数调用NtSetEvent函数,该函数路径为 ReactOS\ntoskrnl\ex\event.c 。
/*
* @implemented
*/
NTSTATUS
NTAPI
NtSetEvent(IN HANDLE EventHandle,
OUT PLONG PreviousState OPTIONAL)
{
PKEVENT Event;
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
NTSTATUS Status;
PAGED_CODE();
DPRINT("NtSetEvent(EventHandle 0%p PreviousState 0%p)\n",
EventHandle, PreviousState);
/* Check if we were called from user-mode */
if ((PreviousState) && (PreviousMode != KernelMode))
{
/* Entry SEH Block */
_SEH2_TRY
{
/* Make sure the state pointer is valid */
ProbeForWriteLong(PreviousState);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Return the exception code */
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
/* Open the Object */
Status = ObReferenceObjectByHandle(EventHandle,
EVENT_MODIFY_STATE,
ExEventObjectType,
PreviousMode,
(PVOID*)&Event,
NULL);
if (NT_SUCCESS(Status))
{
/* Set the Event */
LONG Prev = KeSetEvent(Event, EVENT_INCREMENT, FALSE);
ObDereferenceObject(Event);
/* Check if caller wants the old state back */
if (PreviousState)
{
/* Entry SEH Block for return */
_SEH2_TRY
{
/* Return previous state */
*PreviousState = Prev;
}
_SEH2_EXCEPT(ExSystemExceptionFilter())
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
}
}
/* Return Status */
return Status;
}
NtSetEvent函数较多代码都是SEH异常处理机制。主体部分首先是调用ObReferenceObjectByHandle获取KEVENT内核事件对象,然后调用KeSetEvent,该函数路径为ReactOS\ntoskrnl\ke\eventobj.c。关键部分源代码原本都已经有注释,这里就不画蛇添足了。
/*
* @implemented
*/
LONG
NTAPI
KeSetEvent(IN PKEVENT Event,
IN KPRIORITY Increment,
IN BOOLEAN Wait)
{
KIRQL OldIrql;
LONG PreviousState;
PKTHREAD Thread;
ASSERT_EVENT(Event);
ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
/*
* Check if this is an signaled notification event without an upcoming wait.
* In this case, we can immediately return TRUE, without locking.
*/
if ((Event->Header.Type == EventNotificationObject) &&
(Event->Header.SignalState == 1) &&
!(Wait))
{
/* Return the signal state (TRUE/Signalled) */
return TRUE;
}
/* Lock the Dispathcer Database */
OldIrql = KiAcquireDispatcherLock();
/* Save the Previous State */
PreviousState = Event->Header.SignalState;
/* Set the Event to Signaled */
Event->Header.SignalState = 1;
/* Check if the event just became signaled now, and it has waiters */
if (!(PreviousState) && !(IsListEmpty(&Event->Header.WaitListHead)))
{
/* Check the type of event */
if (Event->Header.Type == EventNotificationObject)
{
/* Unwait the thread */
KxUnwaitThread(&Event->Header, Increment);
}
else
{
/* Otherwise unwait the thread and unsignal the event */
KxUnwaitThreadForEvent(Event, Increment);
}
}
/* Check what wait state was requested */
if (!Wait)
{
/* Wait not requested, release Dispatcher Database and return */
KiReleaseDispatcherLock(OldIrql);
}
else
{
/* Return Locked and with a Wait */
Thread = KeGetCurrentThread();
Thread->WaitNext = TRUE;
Thread->WaitIrql = OldIrql;
}
/* Return the previous State */
return PreviousState;
}