Files
UnrealEngineUWP/Engine/Source/Programs/TestPAL/Private/Parent.cpp
Dmitry Rekman e86138d4ca Refactored FProcHandle API in platform abstraction layer.
- Deprecated FProcHandle::Close() in favor of existing FPlatformProcess::CloseProc() (symmetric to FPlatformProcess::CreateProc()).
- Linux: made FProcHandle instances safe to pass by value.
- Linux: added support for "fire and forget" children, which will not leave zombies (at the expense of extra threads and a leaked thread handle).
- Extended TestPAL with tests for most of the above functionality.

#codereview Michael.Trepka, Josh.Adams, Robert.Manuszewski, Jaroslaw.Surowiec

[CL 2476050 by Dmitry Rekman in Main branch]
2015-03-11 20:10:19 -04:00

105 lines
2.9 KiB
C++

// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
#include "PrivatePCH.h"
#include "Parent.h"
FParent::FParent(int InNumTotalChildren, int InMaxChildrenAtOnce)
: NumTotalChildren(InNumTotalChildren)
, MaxChildrenAtOnce(InMaxChildrenAtOnce)
{
}
FProcHandle FParent::Launch(bool bDetached)
{
// Launch the worker process
int32 PriorityModifier = -1; // below normal
uint32 WorkerId = 0;
FString WorkerName = FPlatformProcess::ExecutableName(false);
FProcHandle WorkerHandle = FPlatformProcess::CreateProc(*WorkerName, TEXT("proc-child"), bDetached, false, false, &WorkerId, PriorityModifier, NULL, NULL);
if (!WorkerHandle.IsValid())
{
// If this doesn't error, the app will hang waiting for jobs that can never be completed
UE_LOG(LogTestPAL, Fatal, TEXT("Couldn't launch %s! Make sure the file is in your binaries folder."), *WorkerName);
}
return WorkerHandle;
}
void FParent::Run()
{
// test launching detached
{
for (int i = 0; i < 100; ++i)
{
UE_LOG(LogTestPAL, Log, TEXT("Launching a detached child to see if we leak a zombie."));
FProcHandle Child = Launch(true);
FPlatformProcess::CloseProc(Child);
}
}
// test stopping children prematurely
{
UE_LOG(LogTestPAL, Log, TEXT("Launching a child to wait for it."));
FProcHandle Child = Launch();
UE_LOG(LogTestPAL, Log, TEXT("Closing child's handle (FPlatformProcess::CloseProc)"));
FPlatformProcess::CloseProc(Child);
}
{
UE_LOG(LogTestPAL, Log, TEXT("Launching a child to terminate it."));
FProcHandle Child = Launch();
UE_LOG(LogTestPAL, Log, TEXT("Sleeping for a bit to let the child ramp up."));
FPlatformProcess::Sleep(0.1f);
UE_LOG(LogTestPAL, Log, TEXT("Terminating the child (FPlatformProcess::TerminateProc())"));
FPlatformProcess::TerminateProc(Child);
UE_LOG(LogTestPAL, Log, TEXT("Closing child's handle (FPlatformProcess::CloseProc)"));
FPlatformProcess::CloseProc(Child);
}
UE_LOG(LogTestPAL, Log, TEXT("Proceeding to test multiple children."));
// test normal working loop
while (NumTotalChildren > 0)
{
// see if there are any new children to spawn
while (Children.Num() < MaxChildrenAtOnce)
{
UE_LOG(LogTestPAL, Log, TEXT("Launching a child (%d more to go)."), NumTotalChildren - 1);
FProcHandle Child = Launch();
UE_LOG(LogTestPAL, Log, TEXT("Launch successful"));
Children.Add(Child);
--NumTotalChildren;
}
// sleep for a while
FPlatformProcess::Sleep(0.5f);
// see if any children have finished
for (int ChildIdx = 0; ChildIdx < Children.Num();)
{
int32 ReturnCode = -1;
FProcHandle ChildCopy = Children[ChildIdx];
if (FPlatformProcess::GetProcReturnCode(ChildCopy, &ReturnCode))
{
// print its return code
UE_LOG(LogTestPAL, Log, TEXT("Child finished, return code %d"), ReturnCode);
FPlatformProcess::CloseProc(ChildCopy);
Children.RemoveAt(ChildIdx);
}
else
{
++ChildIdx;
}
}
}
}