patch by Skywing: made existing eventpair code more efficient and added support for associating eventpairs with

threads and signaling them that way

svn path=/trunk/; revision=6031
This commit is contained in:
Vizzini 2003-09-10 06:12:22 +00:00
parent 05023f216e
commit 413af2c984
14 changed files with 397 additions and 12 deletions

View file

@ -14,7 +14,7 @@ lineclip linetest lock lpc messagebox mktime mstest multiwin \
mutex nptest patblt pipe primitives pteb regtest sectest sertest \
shaptest shm statst statst2 stretchblt suspend tcpsvr terminate \
txtscale thread thread_msg tokentest vmtest winhello wm_erasebkgnd \
wm_paint
wm_paint eventpair threadwait
TEST_MISC =

View file

@ -0,0 +1,65 @@
/*
* Author: Skywing (skywing@valhallalegends.com)
* Date: 09/09/2003
* Purpose: Test Thread-EventPair functionality.
*/
#include <windows.h>
#include <stdio.h>
#include <ddk/ntddk.h>
#ifndef NTAPI
#define NTAPI WINAPI
#endif
HANDLE MakeEventPair()
{
NTSTATUS Status;
HANDLE EventPair;
OBJECT_ATTRIBUTES Attributes;
InitializeObjectAttributes(&Attributes, NULL, 0, NULL, NULL);
Status = NtCreateEventPair(&EventPair, STANDARD_RIGHTS_ALL, &Attributes);
printf("Status %08x creating eventpair\n", Status);
return EventPair;
}
DWORD __stdcall threadfunc(void* eventpair)
{
printf("Thread: Set eventpair status %08x\n", NtSetInformationThread(NtCurrentThread(), ThreadEventPair, &eventpair, sizeof(HANDLE)));
Sleep(2500);
printf("Thread: Setting low and waiting high...\n");
printf("Thread: status = %08x\n", NtSetLowWaitHighThread());
printf("Thread: status = %08x\n", NtSetHighWaitLowThread());
printf("Thread: Terminating...\n");
return 0;
}
int main(int ac, char **av)
{
DWORD id;
HANDLE EventPair, Thread;
printf("Main: NtSetLowWaitHighThread is at %08x\n", NtSetLowWaitHighThread);
EventPair = MakeEventPair();
if(!EventPair) {
printf("Main: Could not create event pair.\n");
return 0;
}
printf("Main: EventPair = %08x\n", EventPair);
Thread = CreateThread(0, 0, threadfunc, EventPair, 0, &id);
printf("Main: ThreadId for new thread is %08x\n", id);
printf("Main: Setting high and waiting low\n");
printf("Main: status = %08x\n", NtSetHighWaitLowEventPair(EventPair));
Sleep(2500);
printf("Main: status = %08x\n", NtSetLowWaitHighEventPair(EventPair));
NtClose(EventPair);
/* WaitForSingleObject(Thread, INFINITE); FIXME: Waiting on thread handle causes double spinlock acquisition (and subsequent crash) in PsUnblockThread - ntoskrnl/ps/thread.c */
NtClose(Thread);
printf("Main: Terminating...\n");
return 0;
}

View file

@ -0,0 +1,21 @@
# $Id: makefile,v 1.1 2003/09/10 06:12:21 vizzini Exp $
PATH_TO_TOP = ../../..
TARGET_NORC = yes
TARGET_TYPE = program
TARGET_APPTYPE = console
TARGET_NAME = eventpair
TARGET_SDKLIBS = ntdll.a
TARGET_OBJECTS = $(TARGET_NAME).o
include $(PATH_TO_TOP)/rules.mak
include $(TOOLS_PATH)/helper.mk
# EOF

View file

@ -0,0 +1,21 @@
# $Id: makefile,v 1.1 2003/09/10 06:12:21 vizzini Exp $
PATH_TO_TOP = ../../..
TARGET_NORC = yes
TARGET_TYPE = program
TARGET_APPTYPE = console
TARGET_NAME = threadwait
TARGET_SDKLIBS = ntdll.a
TARGET_OBJECTS = $(TARGET_NAME).o
include $(PATH_TO_TOP)/rules.mak
include $(TOOLS_PATH)/helper.mk
# EOF

View file

@ -0,0 +1,31 @@
/*
* Author: Skywing (skywing@valhallalegends.com)
* Date: 09/09/2003
* Purpose: Probe for PsUnblockThread crash due to double-acquire spin lock.
*/
#include <windows.h>
#include <stdio.h>
DWORD __stdcall threadfunc(void* UNREFERENCED)
{
printf("Thread: Initialized\n");
Sleep(2500);
printf("Thread: Terminating...\n");
return 0;
}
int main(int ac, char **av)
{
DWORD id;
HANDLE Thread;
Thread = CreateThread(0, 0, threadfunc, 0, 0, &id);
printf("Main: ThreadId for new thread is %08x\n", id);
printf("Main: Waiting on thread...\n");
WaitForSingleObject(Thread, INFINITE);
printf("Main: OK, somebody fixed the PsUnblockThread spinlock double-acquire crash\n");
NtClose(Thread);
printf("Main: Terminating...\n");
return 0;
}

View file

@ -159,6 +159,7 @@ NtSetEaFile ZwSetEaFile 16
NtSetEvent ZwSetEvent 8
NtSetHighEventPair ZwSetHighEventPair 4
NtSetHighWaitLowEventPair ZwSetHighWaitLowEventPair 4
NtSetHighWaitLowThread ZwSetHighWaitLowThread 0
NtSetInformationFile ZwSetInformationFile 20
NtSetInformationKey ZwSetInformationKey 16
NtSetInformationObject ZwSetInformationObject 16
@ -169,6 +170,7 @@ NtSetIntervalProfile ZwSetIntervalProfile 8
NtSetLdtEntries ZwSetLdtEntries 24
NtSetLowEventPair ZwSetLowEventPair 4
NtSetLowWaitHighEventPair ZwSetLowWaitHighEventPair 4
NtSetLowWaitHighThread ZwSetLowWaitHighThread 0
NtSetSecurityObject ZwSetSecurityObject 12
NtSetSystemEnvironmentValue ZwSetSystemEnvironmentValue 8
NtSetSystemInformation ZwSetSystemInformation 12

View file

@ -1,5 +1,5 @@
/* $Id: zw.h,v 1.16 2003/09/03 20:14:22 ekohl Exp $
/* $Id: zw.h,v 1.17 2003/09/10 06:12:21 vizzini Exp $
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
@ -12,6 +12,7 @@
* 04/08/98: Added some documentation (Ariadne)
* 14/08/98: Added type TIME and change variable type from [1] to [0]
* 14/09/98: Added for each Nt call a corresponding Zw Call
* 09/08/03: Added ThreadEventPair routines
*/
#ifndef __DDK_ZW_H
@ -3469,6 +3470,41 @@ ZwSetLowWaitHighEventPair(
HANDLE EventPair
);
/* NtSetLowWaitHighThread effectively invokes NtSetLowWaitHighEventPair on the
* event pair of the thread.
*/
NTSTATUS
STDCALL
NtSetLowWaitHighThread(
VOID
);
/* ZwSetLowWaitHighThread effectively invokes ZwSetLowWaitHighEventPair on the
* event pair of the thread.
*/
NTSTATUS
STDCALL
ZwSetLowWaitHighThread(
VOID
);
/* NtSetHighWaitLowThread effectively invokes NtSetHighWaitLowEventPair on the
* event pair of the thread.
*/
NTSTATUS
STDCALL
NtSetHighWaitLowThread(
VOID
);
/* ZwSetHighWaitLowThread effectively invokes ZwSetHighWaitLowEventPair on the
* event pair of the thread.
*/
NTSTATUS
STDCALL
ZwSetHighWaitLowThread(
VOID
);
NTSTATUS
STDCALL
NtSetSecurityObject(

View file

@ -130,6 +130,8 @@ cp apps/tests/nptest/npclient.exe $ROS_INSTALL_TESTS
cp apps/tests/atomtest/atomtest.exe $ROS_INSTALL_TESTS
cp apps/tests/mutex/mutex.exe $ROS_INSTALL/bin
cp apps/tests/winhello/winhello.exe $ROS_INSTALL/bin
cp apps/tests/eventpair/eventpair.exe $ROS_INSTALL_TESTS
cp apps/tests/threadwait/threadwait.exe $ROS_INSTALL_TESTS
cp apps/tests/multiwin/multiwin.exe $ROS_INSTALL/bin
cp apps/tests/wm_paint/wm_paint.exe $ROS_INSTALL_TESTS
cp apps/tests/bitblt/lena.bmp $ROS_INSTALL_TESTS

View file

@ -1,4 +1,4 @@
; $Id: ntdll.def,v 1.109 2003/09/08 09:56:56 weiden Exp $
; $Id: ntdll.def,v 1.110 2003/09/10 06:12:21 vizzini Exp $
;
; ReactOS Operating System
;
@ -222,6 +222,7 @@ NtSetEaFile@16
NtSetEvent@8
NtSetHighEventPair@4
NtSetHighWaitLowEventPair@4
NtSetHighWaitLowThread@0
NtSetInformationFile@20
NtSetInformationKey@16
NtSetInformationObject@16
@ -233,6 +234,7 @@ NtSetIoCompletion@20
NtSetLdtEntries@24
NtSetLowEventPair@4
NtSetLowWaitHighEventPair@4
NtSetLowWaitHighThread@0
NtSetSecurityObject@12
NtSetSystemEnvironmentValue@8
NtSetSystemInformation@12
@ -776,6 +778,7 @@ ZwSetEaFile@16
ZwSetEvent@8
ZwSetHighEventPair@4
ZwSetHighWaitLowEventPair@4
ZwSetHighWaitLowThread@0
ZwSetInformationFile@20
ZwSetInformationKey@16
ZwSetInformationObject@16
@ -787,6 +790,7 @@ ZwSetIoCompletion@20
ZwSetLdtEntries@24
ZwSetLowEventPair@4
ZwSetLowWaitHighEventPair@4
ZwSetLowWaitHighThread@0
ZwSetSecurityObject@12
ZwSetSystemEnvironmentValue@8
ZwSetSystemInformation@12

View file

@ -1,4 +1,4 @@
; $Id: ntdll.edf,v 1.99 2003/09/08 09:56:57 weiden Exp $
; $Id: ntdll.edf,v 1.100 2003/09/10 06:12:21 vizzini Exp $
;
; ReactOS Operating System
;
@ -222,6 +222,7 @@ NtSetEaFile=NtSetEaFile@16
NtSetEvent=NtSetEvent@8
NtSetHighEventPair=NtSetHighEventPair@4
NtSetHighWaitLowEventPair=NtSetHighWaitLowEventPair@4
NtSetHighWaitLowThread=NtSetHighWaitLowThread@0
NtSetInformationFile=NtSetInformationFile@20
NtSetInformationKey=NtSetInformationKey@16
NtSetInformationObject=NtSetInformationObject@16
@ -233,6 +234,7 @@ NtSetIoCompletion=NtSetIoCompletion@20
NtSetLdtEntries=NtSetLdtEntries@24
NtSetLowEventPair=NtSetLowEventPair@4
NtSetLowWaitHighEventPair=NtSetLowWaitHighEventPair@4
NtSetLowWaitHighThread=NtSetLowWaitHighThread@0
NtSetSecurityObject=NtSetSecurityObject@12
NtSetSystemEnvironmentValue=NtSetSystemEnvironmentValue@8
NtSetSystemInformation=NtSetSystemInformation@12
@ -776,6 +778,7 @@ ZwSetEaFile=ZwSetEaFile@16
ZwSetEvent=ZwSetEvent@8
ZwSetHighEventPair=ZwSetHighEventPair@4
ZwSetHighWaitLowEventPair=ZwSetHighWaitLowEventPair@4
ZwSetHighWaitLowThread=ZwSetHighWaitLowThread@0
ZwSetInformationFile=ZwSetInformationFile@20
ZwSetInformationKey=ZwSetInformationKey@16
ZwSetInformationObject=ZwSetInformationObject@16
@ -787,6 +790,7 @@ ZwSetIoCompletion=ZwSetIoCompletion@20
ZwSetLdtEntries=ZwSetLdtEntries@24
ZwSetLowEventPair=ZwSetLowEventPair@4
ZwSetLowWaitHighEventPair=ZwSetLowWaitHighEventPair@4
ZwSetLowWaitHighThread=ZwSetLowWaitHighThread@0
ZwSetSecurityObject=ZwSetSecurityObject@12
ZwSetSystemEnvironmentValue=ZwSetSystemEnvironmentValue@8
ZwSetSystemInformation=ZwSetSystemInformation@12

View file

@ -90,6 +90,8 @@ typedef VOID (*PLOOKASIDE_MINMAX_ROUTINE)(
/* GLOBAL VARIABLES *********************************************************/
TIME_ZONE_INFORMATION SystemTimeZoneInfo;
extern POBJECT_TYPE ExEventPairObjectType;
/* INITIALIZATION FUNCTIONS *************************************************/
@ -105,4 +107,13 @@ ExInitializeWorkerThreads(VOID);
VOID
ExpInitLookasideLists(VOID);
/* OTHER FUNCTIONS **********************************************************/
VOID
ExpSwapThreadEventPair(
IN struct _ETHREAD* Thread,
IN struct _KEVENT_PAIR* EventPair
);
#endif /* __NTOSKRNL_INCLUDE_INTERNAL_EXECUTIVE_H */

View file

@ -1,4 +1,4 @@
/* $Id: evtpair.c,v 1.14 2003/06/07 12:23:14 chorns Exp $
/* $Id: evtpair.c,v 1.15 2003/09/10 06:12:21 vizzini Exp $
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
@ -7,6 +7,10 @@
* PROGRAMMER: David Welch (welch@mcmail.com)
* UPDATE HISTORY:
* Created 22/05/98
* Updated 09/08/2003 by Skywing (skywing@valhallalegends.com)
* to correctly maintain ownership of the dispatcher lock
* between KeSetEvent and KeWaitForSingleObject calls.
* Additionally, implemented the thread-eventpair routines.
*/
/* INCLUDES *****************************************************************/
@ -14,11 +18,20 @@
#define NTOS_MODE_KERNEL
#include <ntos.h>
#include <ntos/synch.h>
#include <internal/ps.h>
#include <limits.h>
#define NDEBUG
#include <internal/debug.h>
#ifndef NTSYSAPI
#define NTSYSAPI
#endif
#ifndef NTAPI
#define NTAPI STDCALL
#endif
/* GLOBALS *******************************************************************/
@ -30,6 +43,8 @@ static GENERIC_MAPPING ExEventPairMapping = {
STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE,
EVENT_PAIR_ALL_ACCESS};
static KSPIN_LOCK ExThreadEventPairSpinLock;
/* FUNCTIONS *****************************************************************/
NTSTATUS STDCALL
@ -72,6 +87,8 @@ VOID NtInitializeEventPairImplementation(VOID)
ExEventPairObjectType->OkayToClose = NULL;
ExEventPairObjectType->Create = NtpCreateEventPair;
ExEventPairObjectType->DuplicationNotify = NULL;
KeInitializeSpinLock(&ExThreadEventPairSpinLock);
}
@ -172,7 +189,7 @@ NtSetHighWaitLowEventPair(IN HANDLE EventPairHandle)
KeSetEvent(&EventPair->HighEvent,
EVENT_INCREMENT,
FALSE);
TRUE);
KeWaitForSingleObject(&EventPair->LowEvent,
WrEventPair,
@ -205,7 +222,7 @@ NtSetLowEventPair(IN HANDLE EventPairHandle)
KeSetEvent(&EventPair->LowEvent,
EVENT_INCREMENT,
FALSE);
TRUE);
ObDereferenceObject(EventPair);
return(STATUS_SUCCESS);
@ -232,7 +249,7 @@ NtSetLowWaitHighEventPair(IN HANDLE EventPairHandle)
KeSetEvent(&EventPair->LowEvent,
EVENT_INCREMENT,
FALSE);
TRUE);
KeWaitForSingleObject(&EventPair->HighEvent,
WrEventPair,
@ -302,4 +319,139 @@ NtWaitHighEventPair(IN HANDLE EventPairHandle)
return(STATUS_SUCCESS);
}
/*
* Author: Skywing (skywing@valhallalegends.com), 09/08/2003
* Note that the eventpair spinlock must be acquired when setting the thread
* eventpair via NtSetInformationThread.
* @implemented
*/
NTSYSAPI
NTSTATUS
NTAPI
NtSetLowWaitHighThread(
VOID
)
{
PETHREAD Thread;
PKEVENT_PAIR EventPair;
NTSTATUS Status;
KIRQL Irql;
Thread = PsGetCurrentThread();
if(!Thread->EventPair)
return STATUS_NO_EVENT_PAIR;
KeAcquireSpinLock(&ExThreadEventPairSpinLock, &Irql);
EventPair = Thread->EventPair;
if(EventPair)
ObReferenceObjectByPointer(EventPair,
EVENT_PAIR_ALL_ACCESS,
ExEventPairObjectType,
UserMode);
KeReleaseSpinLock(&ExThreadEventPairSpinLock, Irql);
if(EventPair == NULL)
return STATUS_NO_EVENT_PAIR;
KeSetEvent(&EventPair->LowEvent,
EVENT_INCREMENT,
TRUE);
Status = KeWaitForSingleObject(&EventPair->HighEvent,
WrEventPair,
UserMode,
FALSE,
NULL);
ObDereferenceObject(EventPair);
return Status;
}
/*
* Author: Skywing (skywing@valhallalegends.com), 09/08/2003
* Note that the eventpair spinlock must be acquired when setting the thread
* eventpair via NtSetInformationThread.
* @implemented
*/
NTSYSAPI
NTSTATUS
NTAPI
NtSetHighWaitLowThread(
VOID
)
{
PETHREAD Thread;
PKEVENT_PAIR EventPair;
NTSTATUS Status;
KIRQL Irql;
Thread = PsGetCurrentThread();
if(!Thread->EventPair)
return STATUS_NO_EVENT_PAIR;
KeAcquireSpinLock(&ExThreadEventPairSpinLock, &Irql);
EventPair = PsGetCurrentThread()->EventPair;
if(EventPair)
ObReferenceObjectByPointer(EventPair,
EVENT_PAIR_ALL_ACCESS,
ExEventPairObjectType,
UserMode);
KeReleaseSpinLock(&ExThreadEventPairSpinLock, Irql);
if(EventPair == NULL)
return STATUS_NO_EVENT_PAIR;
KeSetEvent(&EventPair->HighEvent,
EVENT_INCREMENT,
TRUE);
Status = KeWaitForSingleObject(&EventPair->LowEvent,
WrEventPair,
UserMode,
FALSE,
NULL);
ObDereferenceObject(EventPair);
return Status;
}
/*
* Author: Skywing (skywing@valhallalegends.com), 09/08/2003
* Note that the eventpair spinlock must be acquired when waiting on the
* eventpair via NtSetLow/HighWaitHigh/LowThread. Additionally, when
* deleting a thread object, NtpSwapThreadEventPair(Thread, NULL) should
* be called to release any preexisting eventpair object associated with
* the thread. The Microsoft name for this function is not known.
*/
VOID
ExpSwapThreadEventPair(
IN PETHREAD Thread,
IN PKEVENT_PAIR EventPair
)
{
PKEVENT_PAIR OriginalEventPair;
KIRQL Irql;
KeAcquireSpinLock(&ExThreadEventPairSpinLock, &Irql);
OriginalEventPair = Thread->EventPair;
Thread->EventPair = EventPair;
if(OriginalEventPair)
ObDereferenceObject(OriginalEventPair);
KeReleaseSpinLock(&ExThreadEventPairSpinLock, Irql);
}
/* EOF */

View file

@ -1,4 +1,4 @@
/* $Id: create.c,v 1.64 2003/07/21 21:53:53 royce Exp $
/* $Id: create.c,v 1.65 2003/09/10 06:12:22 vizzini Exp $
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
@ -8,6 +8,7 @@
* REVISION HISTORY:
* 23/06/98: Created
* 12/10/99: Phillip Susi: Thread priorities, and APC work
* 09/08/03: Skywing: ThreadEventPair support (delete)
*/
/*
@ -25,6 +26,7 @@
#include <internal/ke.h>
#include <internal/ob.h>
#include <internal/ps.h>
#include <internal/ex.h>
#include <internal/se.h>
#include <internal/id.h>
#include <internal/dbg.h>
@ -310,6 +312,7 @@ PiDeleteThread(PVOID ObjectBody)
PiNrThreads--;
RemoveEntryList(&Thread->Tcb.ThreadListEntry);
KeReleaseSpinLock(&PiThreadListLock, oldIrql);
ExpSwapThreadEventPair(Thread, NULL); /* Release the associated eventpair object, if there was one */
for (i = 0; i < NotifyRoutineCount; i++)
{

View file

@ -1,4 +1,4 @@
/* $Id: tinfo.c,v 1.21 2003/07/11 01:23:15 royce Exp $
/* $Id: tinfo.c,v 1.22 2003/09/10 06:12:22 vizzini Exp $
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
@ -7,12 +7,15 @@
* PROGRAMMER: David Welch (welch@mcmail.com)
* UPDATE HISTORY:
* Created 22/05/98
* Updated 09/08/2003 by Skywing (skywing@valhallalegends.com)
* to suppport thread-eventpairs.
*/
/* INCLUDES *****************************************************************/
#include <ddk/ntddk.h>
#include <internal/ps.h>
#include <internal/ex.h>
#include <internal/safe.h>
#include <internal/debug.h>
@ -106,8 +109,38 @@ NtSetInformationThread(HANDLE ThreadHandle,
break;
case ThreadEventPair:
Status = STATUS_NOT_IMPLEMENTED;
break;
{
PKEVENT_PAIR EventPair;
if (ThreadInformationLength != sizeof(HANDLE))
{
Status = STATUS_INFO_LENGTH_MISMATCH;
break;
}
if (ExGetPreviousMode() == UserMode) /* FIXME: Validate this for all infoclasses and system services */
{
DPRINT("NtSetInformationThread:ThreadEventPair: Checking user pointer %08x...\n", ThreadInformation);
ProbeForRead(ThreadInformation, sizeof(HANDLE), sizeof(HANDLE)); /* FIXME: This entire function should be
* wrapped in an SEH frame... return (NTSTATUS)GetExceptionCode() on exception */
}
Status = ObReferenceObjectByHandle(*(PHANDLE)ThreadInformation,
STANDARD_RIGHTS_ALL,
ExEventPairObjectType,
ExGetPreviousMode(),
(PVOID*)&EventPair,
NULL);
if (!NT_SUCCESS(Status))
{
break;
}
ExpSwapThreadEventPair(Thread, EventPair); /* Note that the extra reference is kept intentionally */
Status = STATUS_SUCCESS;
break;
}
case ThreadQuerySetWin32StartAddress:
if (ThreadInformationLength != sizeof(ULONG))