mirror of
https://github.com/microsoft/WSL.git
synced 2025-07-03 07:23:20 +00:00

Many Microsoft employees have contributed to the Windows Subsystem for Linux, this commit is the result of their work since 2016. The entire history of the Windows Subsystem for Linux can't be shared here, but here's an overview of WSL's history after it moved to it own repository in 2021: Number of commits on the main branch: 2930 Number of contributors: 31 Head over https://github.com/microsoft/WSL/releases for a more detailed history of the features added to WSL since 2021.
289 lines
7.5 KiB
C
289 lines
7.5 KiB
C
/*++
|
|
|
|
Copyright (c) Microsoft. All rights reserved.
|
|
|
|
Module Name:
|
|
|
|
EventFd.c
|
|
|
|
Abstract:
|
|
|
|
This file is a eventfd test.
|
|
|
|
--*/
|
|
|
|
#include "lxtcommon.h"
|
|
#include "unittests.h"
|
|
#include <sys/types.h>
|
|
#include <sys/wait.h>
|
|
#include <sys/epoll.h>
|
|
#include <sys/eventfd.h>
|
|
|
|
#define LXT_NAME "EventFd"
|
|
|
|
#define DEFAULT_USLEEP 5000
|
|
|
|
int EventFdVariationReadWrite(PLXT_ARGS Args);
|
|
|
|
//
|
|
// Global constants
|
|
//
|
|
|
|
static const LXT_VARIATION g_LxtVariations[] = {{"EventFdVariation - read, write", EventFdVariationReadWrite}};
|
|
|
|
int EventfdTestEntry(int Argc, char* Argv[])
|
|
|
|
/*++
|
|
--*/
|
|
|
|
{
|
|
|
|
LXT_ARGS Args;
|
|
int Result;
|
|
|
|
LxtCheckResult(LxtInitialize(Argc, Argv, &Args, LXT_NAME));
|
|
LXT_SYNCHRONIZATION_POINT_INIT();
|
|
LxtCheckResult(LxtRunVariations(&Args, g_LxtVariations, LXT_COUNT_OF(g_LxtVariations)));
|
|
|
|
ErrorExit:
|
|
LXT_SYNCHRONIZATION_POINT_DESTROY();
|
|
LxtUninitialize();
|
|
return !LXT_SUCCESS(Result);
|
|
}
|
|
|
|
int EventFdVariationReadWrite(PLXT_ARGS Args)
|
|
|
|
/*++
|
|
--*/
|
|
|
|
{
|
|
|
|
pid_t ChildPid;
|
|
struct epoll_event EpollEvent;
|
|
int EpollFd;
|
|
int Fd;
|
|
int Index;
|
|
fd_set ReadFds;
|
|
int Result;
|
|
ssize_t Size;
|
|
int Status;
|
|
struct timeval Timeout;
|
|
uint64_t Value;
|
|
uint64_t Values[] = {1, 2, 10, 0xFFFFFFFF, 0xFFFFFFFFFFFFFFFE};
|
|
struct
|
|
{
|
|
uint64_t Value;
|
|
char Buffer[32];
|
|
} LargeValue;
|
|
|
|
EpollFd = -1;
|
|
LXT_SYNCHRONIZATION_POINT_START();
|
|
|
|
//
|
|
// FIXME: Add 0 varaition
|
|
//
|
|
|
|
//
|
|
// Write the values to the event and read them back out single threaded.
|
|
//
|
|
|
|
LxtCheckErrno(Fd = eventfd(0, 0));
|
|
for (Index = 0; Index < LXT_COUNT_OF(Values); Index += 1)
|
|
{
|
|
|
|
//
|
|
// Verify that the event is not ready for read (value is zero).
|
|
//
|
|
|
|
memset(&Timeout, 0, sizeof(Timeout));
|
|
FD_ZERO(&ReadFds);
|
|
FD_SET(Fd, &ReadFds);
|
|
LxtCheckErrno(select((Fd + 1), &ReadFds, NULL, NULL, &Timeout));
|
|
LxtCheckEqual(Result, 0, "%d");
|
|
|
|
Value = Values[Index];
|
|
Size = write(Fd, &Value, sizeof(Value));
|
|
LxtCheckEqual(Size, sizeof(Value), "%lld");
|
|
LxtCheckEqual(Value, Values[Index], "%llu");
|
|
|
|
//
|
|
// Verify that the event is ready for read (value is NOT zero).
|
|
//
|
|
|
|
memset(&Timeout, 0, sizeof(Timeout));
|
|
FD_ZERO(&ReadFds);
|
|
FD_SET(Fd, &ReadFds);
|
|
LxtCheckErrno(select((Fd + 1), &ReadFds, NULL, NULL, &Timeout));
|
|
LxtCheckEqual(Result, 1, "%d");
|
|
|
|
//
|
|
// Check again to verify nothing has changed.
|
|
//
|
|
|
|
memset(&Timeout, 0, sizeof(Timeout));
|
|
FD_ZERO(&ReadFds);
|
|
FD_SET(Fd, &ReadFds);
|
|
LxtCheckErrno(select((Fd + 1), &ReadFds, NULL, NULL, &Timeout));
|
|
LxtCheckEqual(Result, 1, "%d");
|
|
|
|
Value = 0;
|
|
Size = read(Fd, &Value, sizeof(Value));
|
|
LxtCheckEqual(Size, sizeof(Value), "%lld");
|
|
LxtCheckEqual(Value, Values[Index], "%llu");
|
|
}
|
|
|
|
//
|
|
// Verify that the event is not ready for read (value is zero).
|
|
//
|
|
|
|
memset(&Timeout, 0, sizeof(Timeout));
|
|
FD_ZERO(&ReadFds);
|
|
FD_SET(Fd, &ReadFds);
|
|
LxtCheckErrno(select((Fd + 1), &ReadFds, NULL, NULL, &Timeout));
|
|
LxtCheckEqual(Result, 0, "%d");
|
|
|
|
//
|
|
// Write the values to the event and read them back out on another thread.
|
|
//
|
|
|
|
LxtCheckErrno(ChildPid = fork());
|
|
if (ChildPid == 0)
|
|
{
|
|
LxtCheckErrno(EpollFd = epoll_create(1));
|
|
EpollEvent.events = EPOLLIN | EPOLLET;
|
|
EpollEvent.data.fd = Fd;
|
|
LxtCheckErrno(epoll_ctl(EpollFd, EPOLL_CTL_ADD, Fd, &EpollEvent));
|
|
}
|
|
|
|
LXT_SYNCHRONIZATION_POINT();
|
|
for (Index = 0; Index < LXT_COUNT_OF(Values); Index += 1)
|
|
{
|
|
if (ChildPid == 0)
|
|
{
|
|
|
|
//
|
|
// Ignore the first value completely and don't read the second
|
|
// value to verify that epoll edge-triggered behavior is working as
|
|
// expected.
|
|
//
|
|
|
|
if (Index > 0)
|
|
{
|
|
if (Index == 1)
|
|
{
|
|
|
|
//
|
|
// Since the first write was ignored, need to make sure
|
|
// that the second has completed so that the edge-triggered
|
|
// epoll logic works as expected instead of racing with the
|
|
// next write.
|
|
//
|
|
|
|
LXT_SYNCHRONIZATION_POINT();
|
|
}
|
|
|
|
LxtLogInfo("Waiting from child thread...");
|
|
LxtCheckErrno(epoll_wait(EpollFd, &EpollEvent, 1, -1));
|
|
LxtCheckEqual(Result, 1, "%d") LxtCheckEqual(EpollEvent.data.fd, Fd, "%d");
|
|
|
|
//
|
|
// The epoll should be blocked.
|
|
//
|
|
|
|
LxtCheckErrno(epoll_wait(EpollFd, &EpollEvent, 1, 0));
|
|
LxtCheckEqual(Result, 0, "%d");
|
|
|
|
//
|
|
// Skip the first two values to verify epoll edge-triggered
|
|
// behavior and then start verifying the value data.
|
|
//
|
|
|
|
if (Index > 1)
|
|
{
|
|
Value = 0;
|
|
Size = read(Fd, &Value, sizeof(Value));
|
|
LxtCheckEqual(Size, sizeof(Value), "%lld");
|
|
if (Index == 2)
|
|
{
|
|
LxtCheckEqual(Value, (Values[0] + Values[1] + Values[2]), "%llu");
|
|
}
|
|
else
|
|
{
|
|
LxtCheckEqual(Value, Values[Index], "%llu");
|
|
}
|
|
}
|
|
|
|
//
|
|
// The epoll should still be blocked.
|
|
//
|
|
|
|
LxtCheckErrno(epoll_wait(EpollFd, &EpollEvent, 1, 0));
|
|
LxtCheckEqual(Result, 0, "%d")
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LxtLogInfo("Writing 0x%llx from parent thread...", Values[Index]);
|
|
Value = Values[Index];
|
|
Size = write(Fd, &Value, sizeof(Value));
|
|
LxtCheckEqual(Size, sizeof(Value), "%lld");
|
|
LxtCheckEqual(Value, Values[Index], "%llu");
|
|
if (Index == 1)
|
|
{
|
|
LXT_SYNCHRONIZATION_POINT();
|
|
}
|
|
}
|
|
|
|
LXT_SYNCHRONIZATION_POINT();
|
|
}
|
|
|
|
if (ChildPid == 0)
|
|
{
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Read and write out with a buffer larger than the default.
|
|
//
|
|
|
|
memset(&LargeValue, 0, sizeof(LargeValue));
|
|
LargeValue.Value = 1;
|
|
Size = write(Fd, &LargeValue, sizeof(LargeValue));
|
|
LxtCheckEqual(Size, sizeof(LargeValue.Value), "%lld");
|
|
LxtCheckEqual(LargeValue.Value, 1, "%llu");
|
|
|
|
LargeValue.Value = 0;
|
|
Size = read(Fd, &LargeValue, sizeof(LargeValue));
|
|
LxtCheckEqual(Size, sizeof(LargeValue.Value), "%lld");
|
|
LxtCheckEqual(LargeValue.Value, 1, "%llu");
|
|
|
|
//
|
|
// Check the error code for writing the maximum value.
|
|
//
|
|
|
|
Value = 0xFFFFFFFFFFFFFFFF;
|
|
LxtCheckErrnoFailure(write(Fd, &Value, sizeof(Value)), EINVAL);
|
|
|
|
//
|
|
// Check the error code for reading and writing a size of 0.
|
|
//
|
|
|
|
LxtCheckErrnoFailure(read(Fd, &Value, 0), EINVAL);
|
|
LxtCheckErrnoFailure(write(Fd, &Value, 0), EINVAL);
|
|
|
|
Result = LXT_RESULT_SUCCESS;
|
|
|
|
ErrorExit:
|
|
if (Fd > 0)
|
|
{
|
|
close(Fd);
|
|
}
|
|
|
|
if (EpollFd > 0)
|
|
{
|
|
close(EpollFd);
|
|
}
|
|
|
|
LXT_SYNCHRONIZATION_POINT_END();
|
|
return Result;
|
|
}
|