mirror of
https://github.com/Ylianst/MeshAgent
synced 2025-12-10 21:33:38 +00:00
1414 lines
52 KiB
C
1414 lines
52 KiB
C
/*
|
|
Copyright 2006 - 2018 Intel Corporation
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
#ifdef MEMORY_CHECK
|
|
#include <assert.h>
|
|
#define MEMCHECK(x) x
|
|
#else
|
|
#define MEMCHECK(x)
|
|
#endif
|
|
|
|
#if defined(WIN32) && !defined(_WIN32_WCE)
|
|
#define _CRTDBG_MAP_ALLOC
|
|
#include <crtdbg.h>
|
|
#endif
|
|
|
|
|
|
#include "ILibParsers.h"
|
|
#include "ILibRemoteLogging.h"
|
|
#include "ILibProcessPipe.h"
|
|
#include <assert.h>
|
|
#ifndef WIN32
|
|
#include <fcntl.h> /* Obtain O_* constant definitions */
|
|
#include <unistd.h>
|
|
#include <sys/types.h>
|
|
#include <sys/wait.h>
|
|
#include <pty.h>
|
|
#endif
|
|
|
|
#define CONSOLE_SCREEN_WIDTH 80
|
|
#define CONSOLE_SCREEN_HEIGHT 25
|
|
|
|
typedef struct ILibProcessPipe_Manager_Object
|
|
{
|
|
ILibChain_Link ChainLink;
|
|
ILibLinkedList ActivePipes;
|
|
|
|
#ifdef WIN32
|
|
int abort;
|
|
HANDLE updateEvent;
|
|
HANDLE workerThread;
|
|
DWORD workerThreadID;
|
|
void *activeWaitHandle;
|
|
#endif
|
|
}ILibProcessPipe_Manager_Object;
|
|
struct ILibProcessPipe_PipeObject;
|
|
|
|
typedef void(*ILibProcessPipe_GenericReadHandler)(char *buffer, int bufferLen, int* bytesConsumed, void* user1, void* user2);
|
|
typedef void(*ILibProcessPipe_GenericSendOKHandler)(void* user1, void* user2);
|
|
typedef void(*ILibProcessPipe_GenericBrokenPipeHandler)(struct ILibProcessPipe_PipeObject* sender);
|
|
struct ILibProcessPipe_Process_Object; // Forward Prototype
|
|
|
|
typedef struct ILibProcessPipe_PipeObject
|
|
{
|
|
char* buffer;
|
|
int bufferSize;
|
|
|
|
int readOffset;
|
|
int totalRead;
|
|
int processingLoop;
|
|
|
|
ILibProcessPipe_Manager_Object *manager;
|
|
struct ILibProcessPipe_Process_Object* mProcess;
|
|
ILibQueue WriteBuffer;
|
|
void *handler;
|
|
ILibProcessPipe_GenericBrokenPipeHandler brokenPipeHandler;
|
|
void *user1, *user2;
|
|
#ifdef WIN32
|
|
HANDLE mPipe_Reader_ResumeEvent;
|
|
HANDLE mPipe_ReadEnd;
|
|
HANDLE mPipe_WriteEnd;
|
|
struct _OVERLAPPED *mOverlapped;
|
|
void *mOverlapped_opaqueData;
|
|
#else
|
|
int mPipe_ReadEnd, mPipe_WriteEnd;
|
|
#endif
|
|
int PAUSED;
|
|
}ILibProcessPipe_PipeObject;
|
|
|
|
|
|
|
|
typedef struct ILibProcessPipe_Process_Object
|
|
{
|
|
int exiting;
|
|
unsigned int flags1, flags2;
|
|
ILibProcessPipe_Manager_Object *parent;
|
|
#ifdef WIN32
|
|
DWORD PID;
|
|
#else
|
|
pid_t PID;
|
|
#endif
|
|
void *userObject;
|
|
|
|
ILibProcessPipe_PipeObject *stdIn;
|
|
ILibProcessPipe_PipeObject *stdOut;
|
|
ILibProcessPipe_PipeObject *stdErr;
|
|
ILibProcessPipe_Process_ExitHandler exitHandler;
|
|
#ifdef WIN32
|
|
HANDLE hProcess;
|
|
int hProcess_needAdd;
|
|
#endif
|
|
void *chain;
|
|
}ILibProcessPipe_Process_Object;
|
|
|
|
typedef struct ILibProcessPipe_WriteData
|
|
{
|
|
char *buffer;
|
|
int bufferLen;
|
|
ILibTransport_MemoryOwnership ownership;
|
|
}ILibProcessPipe_WriteData;
|
|
|
|
const int ILibMemory_ILibProcessPipe_Pipe_CONTAINERSIZE = sizeof(ILibProcessPipe_PipeObject);
|
|
|
|
ILibProcessPipe_WriteData* ILibProcessPipe_WriteData_Create(char* buffer, int bufferLen, ILibTransport_MemoryOwnership ownership)
|
|
{
|
|
ILibProcessPipe_WriteData* retVal;
|
|
|
|
if ((retVal = (ILibProcessPipe_WriteData*)malloc(sizeof(ILibProcessPipe_WriteData))) == NULL) { ILIBCRITICALEXIT(254); }
|
|
memset(retVal, 0, sizeof(ILibProcessPipe_WriteData));
|
|
retVal->bufferLen = bufferLen;
|
|
if (ownership == ILibTransport_MemoryOwnership_USER)
|
|
{
|
|
if ((retVal->buffer = (char*)malloc(bufferLen)) == NULL) { ILIBCRITICALEXIT(254); }
|
|
memcpy_s(retVal->buffer, bufferLen, buffer, bufferLen);
|
|
retVal->ownership = ILibTransport_MemoryOwnership_CHAIN;
|
|
}
|
|
else
|
|
{
|
|
retVal->buffer = buffer;
|
|
retVal->ownership = ownership;
|
|
}
|
|
return retVal;
|
|
}
|
|
#define ILibProcessPipe_WriteData_Destroy(writeData) if (writeData->ownership == ILibTransport_MemoryOwnership_CHAIN) { free(writeData->buffer); } free(writeData);
|
|
ILibProcessPipe_Pipe ILibProcessPipe_Process_GetStdErr(ILibProcessPipe_Process p)
|
|
{
|
|
return(((ILibProcessPipe_Process_Object*)p)->stdErr);
|
|
}
|
|
ILibProcessPipe_Pipe ILibProcessPipe_Process_GetStdOut(ILibProcessPipe_Process p)
|
|
{
|
|
return(((ILibProcessPipe_Process_Object*)p)->stdOut);
|
|
}
|
|
|
|
#ifdef WIN32
|
|
BOOL ILibProcessPipe_Process_OnExit(HANDLE event, void* user);
|
|
typedef struct ILibProcessPipe_WaitHandle
|
|
{
|
|
ILibProcessPipe_Manager_Object *parent;
|
|
HANDLE event;
|
|
void *user;
|
|
ILibProcessPipe_WaitHandle_Handler callback;
|
|
}ILibProcessPipe_WaitHandle;
|
|
HANDLE ILibProcessPipe_Manager_GetWorkerThread(ILibProcessPipe_Manager mgr)
|
|
{
|
|
return(((ILibProcessPipe_Manager_Object*)mgr)->workerThread);
|
|
}
|
|
|
|
int ILibProcessPipe_Manager_WindowsWaitHandles_Remove_Comparer(void *source, void *matchWith)
|
|
{
|
|
if (source == NULL) { return 1; }
|
|
return(((ILibProcessPipe_WaitHandle*)source)->event == matchWith ? 0 : 1);
|
|
}
|
|
|
|
void __stdcall ILibProcessPipe_WaitHandle_Remove_APC(ULONG_PTR obj)
|
|
{
|
|
ILibProcessPipe_Manager_Object *manager = (ILibProcessPipe_Manager_Object*)((void**)obj)[0];
|
|
HANDLE event = (HANDLE)((void**)obj)[1];
|
|
void *node = ILibLinkedList_GetNode_Search(manager->ActivePipes, ILibProcessPipe_Manager_WindowsWaitHandles_Remove_Comparer, event);
|
|
ILibProcessPipe_WaitHandle *waiter;
|
|
|
|
if (node != NULL)
|
|
{
|
|
waiter = (ILibProcessPipe_WaitHandle*)ILibLinkedList_GetDataFromNode(node);
|
|
free(waiter);
|
|
ILibLinkedList_Remove(node);
|
|
SetEvent(manager->updateEvent);
|
|
}
|
|
free((void*)obj);
|
|
}
|
|
void ILibProcessPipe_WaitHandle_Remove(ILibProcessPipe_Manager mgr, HANDLE event)
|
|
{
|
|
ILibProcessPipe_Manager_Object *manager = (ILibProcessPipe_Manager_Object*)mgr;
|
|
void **data = (void**)ILibMemory_Allocate(2 * sizeof(void*), 0, NULL, NULL);
|
|
data[0] = manager;
|
|
data[1] = event;
|
|
|
|
QueueUserAPC((PAPCFUNC)ILibProcessPipe_WaitHandle_Remove_APC, manager->workerThread, (ULONG_PTR)data);
|
|
}
|
|
void __stdcall ILibProcessPipe_WaitHandle_Add_APC(ULONG_PTR obj)
|
|
{
|
|
ILibProcessPipe_WaitHandle *waitHandle = (ILibProcessPipe_WaitHandle*)obj;
|
|
ILibLinkedList_AddTail(waitHandle->parent->ActivePipes, waitHandle);
|
|
}
|
|
void ILibProcessPipe_WaitHandle_AddEx(ILibProcessPipe_Manager mgr, ILibProcessPipe_WaitHandle *waitHandle)
|
|
{
|
|
ILibProcessPipe_Manager_Object *manager = (ILibProcessPipe_Manager_Object*)mgr;
|
|
if (manager->workerThreadID == GetCurrentThreadId())
|
|
{
|
|
// We're on the same thread, so we can just add it in
|
|
ILibLinkedList_AddTail(manager->ActivePipes, waitHandle);
|
|
|
|
SetEvent(manager->updateEvent);
|
|
}
|
|
else
|
|
{
|
|
// We're on a different thread, so we need to dispatch to the worker thread
|
|
QueueUserAPC((PAPCFUNC)ILibProcessPipe_WaitHandle_Add_APC, manager->workerThread, (ULONG_PTR)waitHandle);
|
|
}
|
|
}
|
|
void ILibProcessPipe_WaitHandle_Add(ILibProcessPipe_Manager mgr, HANDLE event, void *user, ILibProcessPipe_WaitHandle_Handler callback)
|
|
{
|
|
ILibProcessPipe_Manager_Object *manager = (ILibProcessPipe_Manager_Object*)mgr;
|
|
ILibProcessPipe_WaitHandle *waitHandle;
|
|
waitHandle = (ILibProcessPipe_WaitHandle*)ILibMemory_Allocate(sizeof(ILibProcessPipe_WaitHandle), 0, NULL, NULL);
|
|
|
|
waitHandle->parent = manager;
|
|
waitHandle->event = event;
|
|
waitHandle->user = user;
|
|
waitHandle->callback = callback;
|
|
|
|
ILibProcessPipe_WaitHandle_AddEx(mgr, waitHandle);
|
|
}
|
|
|
|
void ILibProcessPipe_Manager_WindowsRunLoopEx(void *arg)
|
|
{
|
|
ILibProcessPipe_Manager_Object *manager = (ILibProcessPipe_Manager_Object*)arg;
|
|
HANDLE hList[FD_SETSIZE * (2*sizeof(HANDLE))];
|
|
ILibLinkedList active = manager->ActivePipes;
|
|
|
|
void* node;
|
|
ILibProcessPipe_WaitHandle* data;
|
|
|
|
int i;
|
|
DWORD x;
|
|
|
|
memset(hList, 0, sizeof(HANDLE)*FD_SETSIZE);
|
|
manager->workerThreadID = GetCurrentThreadId();
|
|
|
|
while (manager->abort == 0)
|
|
{
|
|
hList[0] = manager->updateEvent;
|
|
i = 1;
|
|
|
|
|
|
//Prepare the rest of the WaitHandle Array, for the WaitForMultipleObject call
|
|
node = ILibLinkedList_GetNode_Head(active);
|
|
while (node != NULL)
|
|
{
|
|
if ((data = (ILibProcessPipe_WaitHandle*)ILibLinkedList_GetDataFromNode(node)) != NULL)
|
|
{
|
|
ILibRemoteLogging_printf(ILibChainGetLogger(manager->ChainLink.ParentChain), ILibRemoteLogging_Modules_Microstack_Generic, ILibRemoteLogging_Flags_VerbosityLevel_1, "WindowsRunLoopEx(): [%p]", data);
|
|
|
|
hList[i] = data->event;
|
|
hList[i + FD_SETSIZE] = (HANDLE)data;
|
|
++i;
|
|
}
|
|
node = ILibLinkedList_GetNextNode(node);
|
|
}
|
|
|
|
ILibRemoteLogging_printf(ILibChainGetLogger(manager->ChainLink.ParentChain), ILibRemoteLogging_Modules_Microstack_Generic, ILibRemoteLogging_Flags_VerbosityLevel_1, "WindowsRunLoopEx(): Number of Handles: %d", i);
|
|
|
|
while ((x = WaitForMultipleObjectsEx(i, hList, FALSE, INFINITE, TRUE)) != WAIT_IO_COMPLETION)
|
|
{
|
|
if (x == WAIT_FAILED || (x-WAIT_OBJECT_0) == 0) { break; }
|
|
data = (ILibProcessPipe_WaitHandle*)hList[x + FD_SETSIZE];
|
|
manager->activeWaitHandle = data;
|
|
if (data != NULL && data->callback != NULL) { data->callback(data->event, data->user); }
|
|
}
|
|
ResetEvent(manager->updateEvent);
|
|
}
|
|
|
|
//
|
|
// We need to enumerate the list of handles, and free them, because now that this thread
|
|
// is not in an alertable state, the parent will not be able to Queue any actions for cleanup
|
|
//
|
|
while ((node = ILibLinkedList_GetNode_Head(manager->ActivePipes)) != NULL)
|
|
{
|
|
free(ILibLinkedList_GetDataFromNode(node));
|
|
ILibLinkedList_Remove(node);
|
|
}
|
|
}
|
|
ILibProcessPipe_Manager_WindowsRunLoop(void *arg)
|
|
{
|
|
CONTEXT winException;
|
|
__try
|
|
{
|
|
ILibProcessPipe_Manager_WindowsRunLoopEx(arg);
|
|
}
|
|
__except (ILib_WindowsExceptionFilter(GetExceptionCode(), GetExceptionInformation(), &winException))
|
|
{
|
|
ILib_WindowsExceptionDebug(&winException);
|
|
}
|
|
}
|
|
void ILibProcessPipe_Manager_Start(void* chain, void* user)
|
|
{
|
|
ILibProcessPipe_Manager_Object* man = (ILibProcessPipe_Manager_Object*)user;
|
|
|
|
UNREFERENCED_PARAMETER(chain);
|
|
man->workerThread = ILibSpawnNormalThread((voidfp1)&ILibProcessPipe_Manager_WindowsRunLoop, user);
|
|
}
|
|
#else
|
|
void ILibProcessPipe_Process_ReadHandler(void* user);
|
|
void ILibProcessPipe_Manager_OnPreSelect(void* object, fd_set *readset, fd_set *writeset, fd_set *errorset, int* blocktime)
|
|
{
|
|
ILibProcessPipe_Manager_Object *man = (ILibProcessPipe_Manager_Object*)object;
|
|
void *node;
|
|
ILibProcessPipe_PipeObject *j;
|
|
|
|
node = ILibLinkedList_GetNode_Head(man->ActivePipes);
|
|
while(node != NULL && (j = (ILibProcessPipe_PipeObject*)ILibLinkedList_GetDataFromNode(node)) != NULL)
|
|
{
|
|
FD_SET(j->mPipe_ReadEnd, readset);
|
|
node = ILibLinkedList_GetNextNode(node);
|
|
}
|
|
|
|
}
|
|
void ILibProcessPipe_Manager_OnPostSelect(void* object, int slct, fd_set *readset, fd_set *writeset, fd_set *errorset)
|
|
{
|
|
ILibProcessPipe_Manager_Object *man = (ILibProcessPipe_Manager_Object*)object;
|
|
void *node, *nextNode;
|
|
ILibProcessPipe_PipeObject *j;
|
|
|
|
node = ILibLinkedList_GetNode_Head(man->ActivePipes);
|
|
while(node != NULL && (j = (ILibProcessPipe_PipeObject*)ILibLinkedList_GetDataFromNode(node)) != NULL)
|
|
{
|
|
nextNode = ILibLinkedList_GetNextNode(node);
|
|
if(FD_ISSET(j->mPipe_ReadEnd, readset) != 0)
|
|
{
|
|
ILibProcessPipe_Process_ReadHandler(j);
|
|
}
|
|
|
|
node = nextNode;
|
|
}
|
|
}
|
|
#endif
|
|
void ILibProcessPipe_Manager_OnDestroy(void *object)
|
|
{
|
|
ILibProcessPipe_Manager_Object *man = (ILibProcessPipe_Manager_Object*)object;
|
|
|
|
#ifdef WIN32
|
|
man->abort = 1;
|
|
SetEvent(man->updateEvent);
|
|
WaitForSingleObject(man->workerThread, INFINITE);
|
|
#endif
|
|
|
|
ILibLinkedList_Destroy(man->ActivePipes);
|
|
}
|
|
ILibProcessPipe_Manager ILibProcessPipe_Manager_Create(void *chain)
|
|
{
|
|
ILibProcessPipe_Manager_Object *retVal;
|
|
|
|
if ((retVal = (ILibProcessPipe_Manager_Object*)malloc(sizeof(ILibProcessPipe_Manager_Object))) == NULL) { ILIBCRITICALEXIT(254); }
|
|
memset(retVal, 0, sizeof(ILibProcessPipe_Manager_Object));
|
|
|
|
retVal->ChainLink.ParentChain = chain;
|
|
retVal->ActivePipes = ILibLinkedList_Create();
|
|
|
|
#ifdef WIN32
|
|
retVal->updateEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
ILibChain_RunOnMicrostackThread(chain, ILibProcessPipe_Manager_Start, retVal);
|
|
#else
|
|
retVal->ChainLink.PreSelectHandler = &ILibProcessPipe_Manager_OnPreSelect;
|
|
retVal->ChainLink.PostSelectHandler = &ILibProcessPipe_Manager_OnPostSelect;
|
|
#endif
|
|
retVal->ChainLink.DestroyHandler = &ILibProcessPipe_Manager_OnDestroy;
|
|
|
|
if (ILibIsChainRunning(chain) == 0)
|
|
{
|
|
ILibAddToChain(chain, retVal);
|
|
}
|
|
else
|
|
{
|
|
ILibChain_SafeAdd(chain, retVal);
|
|
}
|
|
return retVal;
|
|
}
|
|
|
|
void ILibProcessPipe_FreePipe(ILibProcessPipe_PipeObject *pipeObject)
|
|
{
|
|
#ifdef WIN32
|
|
if (pipeObject->mPipe_ReadEnd != NULL) { CloseHandle(pipeObject->mPipe_ReadEnd); }
|
|
if (pipeObject->mPipe_WriteEnd != NULL) { CloseHandle(pipeObject->mPipe_WriteEnd); }
|
|
if (pipeObject->mOverlapped != NULL) { CloseHandle(pipeObject->mOverlapped->hEvent); free(pipeObject->mOverlapped); }
|
|
if (pipeObject->mPipe_Reader_ResumeEvent != NULL) { CloseHandle(pipeObject->mPipe_Reader_ResumeEvent); }
|
|
#endif
|
|
|
|
if (pipeObject->buffer != NULL) { free(pipeObject->buffer); }
|
|
if (pipeObject->WriteBuffer != NULL)
|
|
{
|
|
ILibProcessPipe_WriteData* data;
|
|
while ((data = (ILibProcessPipe_WriteData*)ILibQueue_DeQueue(pipeObject->WriteBuffer)) != NULL)
|
|
{
|
|
ILibProcessPipe_WriteData_Destroy(data);
|
|
}
|
|
ILibQueue_Destroy(pipeObject->WriteBuffer);
|
|
}
|
|
if (pipeObject->mProcess != NULL)
|
|
{
|
|
if (pipeObject->mProcess->stdIn == pipeObject) { pipeObject->mProcess->stdIn = NULL; }
|
|
if (pipeObject->mProcess->stdOut == pipeObject) { pipeObject->mProcess->stdOut = NULL; }
|
|
if (pipeObject->mProcess->stdErr == pipeObject) { pipeObject->mProcess->stdErr = NULL; }
|
|
}
|
|
free(pipeObject);
|
|
}
|
|
|
|
#ifdef WIN32
|
|
void ILibProcessPipe_PipeObject_DisableInherit(HANDLE* h)
|
|
{
|
|
HANDLE tmpRead = *h;
|
|
DuplicateHandle(GetCurrentProcess(), tmpRead, GetCurrentProcess(), h, 0, FALSE, DUPLICATE_SAME_ACCESS);
|
|
CloseHandle(tmpRead);
|
|
}
|
|
#endif
|
|
|
|
#ifdef WIN32
|
|
ILibProcessPipe_Pipe ILibProcessPipe_Pipe_CreateFromExistingWithExtraMemory(ILibProcessPipe_Manager manager, HANDLE existingPipe, ILibProcessPipe_Pipe_ReaderHandleType handleType, int extraMemorySize)
|
|
#else
|
|
ILibProcessPipe_Pipe ILibProcessPipe_Pipe_CreateFromExistingWithExtraMemory(ILibProcessPipe_Manager manager, int existingPipe, int extraMemorySize)
|
|
#endif
|
|
{
|
|
ILibProcessPipe_PipeObject* retVal = NULL;
|
|
|
|
retVal = (ILibProcessPipe_PipeObject*)ILibMemory_Allocate(ILibMemory_ILibProcessPipe_Pipe_CONTAINERSIZE, extraMemorySize, NULL, NULL);
|
|
retVal->manager = (ILibProcessPipe_Manager_Object*)manager;
|
|
|
|
#ifdef WIN32
|
|
if (handleType == ILibProcessPipe_Pipe_ReaderHandleType_Overlapped)
|
|
{
|
|
if ((retVal->mOverlapped = (struct _OVERLAPPED*)malloc(sizeof(struct _OVERLAPPED))) == NULL) { ILIBCRITICALEXIT(254); }
|
|
memset(retVal->mOverlapped, 0, sizeof(struct _OVERLAPPED));
|
|
if ((retVal->mOverlapped->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL)) == NULL) { ILIBCRITICALEXIT(254); }
|
|
}
|
|
#else
|
|
fcntl(existingPipe, F_SETFL, O_NONBLOCK);
|
|
#endif
|
|
|
|
retVal->mPipe_ReadEnd = existingPipe;
|
|
retVal->mPipe_WriteEnd = existingPipe;
|
|
return retVal;
|
|
}
|
|
|
|
void ILibProcessPipe_Pipe_SetBrokenPipeHandler(ILibProcessPipe_Pipe targetPipe, ILibProcessPipe_Pipe_BrokenPipeHandler handler)
|
|
{
|
|
((ILibProcessPipe_PipeObject*)targetPipe)->brokenPipeHandler = (ILibProcessPipe_GenericBrokenPipeHandler)handler;
|
|
}
|
|
|
|
ILibProcessPipe_PipeObject* ILibProcessPipe_CreatePipe(ILibProcessPipe_Manager manager, int pipeBufferSize, ILibProcessPipe_GenericBrokenPipeHandler brokenPipeHandler, int extraMemorySize)
|
|
{
|
|
ILibProcessPipe_PipeObject* retVal = NULL;
|
|
#ifdef WIN32
|
|
unsigned int pipeCounter = 0;
|
|
char pipeName[255];
|
|
SECURITY_ATTRIBUTES saAttr;
|
|
#else
|
|
int fd[2];
|
|
#endif
|
|
|
|
retVal = (ILibProcessPipe_PipeObject*)ILibMemory_Allocate(ILibMemory_ILibProcessPipe_Pipe_CONTAINERSIZE, extraMemorySize, NULL, NULL);
|
|
retVal->brokenPipeHandler = brokenPipeHandler;
|
|
retVal->manager = (ILibProcessPipe_Manager_Object*)manager;
|
|
|
|
#ifdef WIN32
|
|
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
|
saAttr.bInheritHandle = TRUE;
|
|
saAttr.lpSecurityDescriptor = NULL;
|
|
|
|
do
|
|
{
|
|
sprintf_s(pipeName, sizeof(pipeName), "\\\\.\\pipe\\%p%u", (void*)retVal, pipeCounter++);
|
|
retVal->mPipe_ReadEnd = CreateNamedPipeA(pipeName, FILE_FLAG_FIRST_PIPE_INSTANCE | PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE, 1, pipeBufferSize, pipeBufferSize, 0, &saAttr);
|
|
if (retVal->mPipe_ReadEnd == (HANDLE)INVALID_HANDLE_VALUE) { ILIBCRITICALEXIT(254); }
|
|
} while (retVal->mPipe_ReadEnd == (HANDLE)ERROR_ACCESS_DENIED);
|
|
|
|
if ((retVal->mOverlapped = (struct _OVERLAPPED*)malloc(sizeof(struct _OVERLAPPED))) == NULL) { ILIBCRITICALEXIT(254); }
|
|
memset(retVal->mOverlapped, 0, sizeof(struct _OVERLAPPED));
|
|
if ((retVal->mOverlapped->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL)) == NULL) { ILIBCRITICALEXIT(254); }
|
|
|
|
retVal->mPipe_WriteEnd = CreateFileA(pipeName, GENERIC_WRITE, 0, &saAttr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
if (retVal->mPipe_WriteEnd == INVALID_HANDLE_VALUE) { ILIBCRITICALEXIT(254); }
|
|
#else
|
|
if(pipe(fd)==0)
|
|
{
|
|
fcntl(fd[0], F_SETFL, O_NONBLOCK);
|
|
fcntl(fd[1], F_SETFL, O_NONBLOCK);
|
|
retVal->mPipe_ReadEnd = fd[0];
|
|
retVal->mPipe_WriteEnd = fd[1];
|
|
}
|
|
#endif
|
|
|
|
return retVal;
|
|
}
|
|
|
|
#ifdef WIN32
|
|
void __stdcall ILibProcessPipe_Process_Destroy_WinRunThread(ULONG_PTR obj)
|
|
{
|
|
ILibProcessPipe_Process_Object *p = (ILibProcessPipe_Process_Object*)obj;
|
|
if (p->exiting != 0) { return; }
|
|
if (p->stdIn != NULL) { ILibProcessPipe_FreePipe(p->stdIn); }
|
|
if (p->stdOut != NULL) { ILibProcessPipe_FreePipe(p->stdOut); }
|
|
if (p->stdErr != NULL) { ILibProcessPipe_FreePipe(p->stdErr); }
|
|
free(p);
|
|
}
|
|
#endif
|
|
void ILibProcessPipe_Process_Destroy(ILibProcessPipe_Process_Object *p)
|
|
{
|
|
#ifdef WIN32
|
|
// We can't destroy this now, because we're on the MicrostackThread. We must destroy this on the WindowsRunLoop Thread.
|
|
QueueUserAPC((PAPCFUNC)ILibProcessPipe_Process_Destroy_WinRunThread, p->parent->workerThread, (ULONG_PTR)p);
|
|
#else
|
|
if (p->exiting != 0) { return; }
|
|
if (p->stdIn != NULL) { ILibProcessPipe_FreePipe(p->stdIn); }
|
|
if (p->stdOut != NULL) { ILibProcessPipe_FreePipe(p->stdOut); }
|
|
if (p->stdErr != NULL) { ILibProcessPipe_FreePipe(p->stdErr); }
|
|
free(p);
|
|
#endif
|
|
}
|
|
#ifndef WIN32
|
|
void ILibProcessPipe_Process_BrokenPipeSink(ILibProcessPipe_Pipe sender)
|
|
{
|
|
ILibProcessPipe_Process_Object *p = ((ILibProcessPipe_PipeObject*)sender)->mProcess;
|
|
int status;
|
|
if (ILibIsRunningOnChainThread(((ILibProcessPipe_PipeObject*)sender)->manager->ChainLink.ParentChain) != 0)
|
|
{
|
|
// This was called from the Reader
|
|
if (p->exitHandler != NULL)
|
|
{
|
|
waitpid((pid_t)p->PID, &status, 0);
|
|
p->exitHandler(p, WEXITSTATUS(status), p->userObject);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
void* ILibProcessPipe_Process_KillEx(ILibProcessPipe_Process p)
|
|
{
|
|
void *retVal = ILibProcessPipe_Process_Kill(p);
|
|
ILibProcessPipe_Process_Destroy((ILibProcessPipe_Process_Object*)p);
|
|
return retVal;
|
|
}
|
|
void ILibProcessPipe_Process_SoftKill(ILibProcessPipe_Process p)
|
|
{
|
|
ILibProcessPipe_Process_Object* j = (ILibProcessPipe_Process_Object*)p;
|
|
#ifdef WIN32
|
|
TerminateProcess(j->hProcess, 1067);
|
|
#else
|
|
int code;
|
|
kill((pid_t)j->PID, SIGKILL);
|
|
waitpid((pid_t)j->PID, &code, 0);
|
|
#endif
|
|
}
|
|
void* ILibProcessPipe_Process_Kill(ILibProcessPipe_Process p)
|
|
{
|
|
ILibProcessPipe_Process_Object* j = (ILibProcessPipe_Process_Object*)p;
|
|
|
|
#ifdef WIN32
|
|
// First things first, unhook all the pipes from the Windows Run Loop
|
|
if (ILibIsChainBeingDestroyed(j->chain) == 0)
|
|
{
|
|
if (j->stdIn != NULL && j->stdIn->mOverlapped != NULL) { ILibProcessPipe_WaitHandle_Remove(j->parent, j->stdIn->mOverlapped->hEvent); }
|
|
if (j->stdOut != NULL && j->stdOut->mOverlapped != NULL) { ILibProcessPipe_WaitHandle_Remove(j->parent, j->stdOut->mOverlapped->hEvent); }
|
|
if (j->stdErr != NULL && j->stdErr->mOverlapped != NULL) { ILibProcessPipe_WaitHandle_Remove(j->parent, j->stdErr->mOverlapped->hEvent); }
|
|
if (j->hProcess != NULL) { ILibProcessPipe_WaitHandle_Remove(j->parent, j->hProcess); TerminateProcess(j->hProcess, 1067); }
|
|
}
|
|
else
|
|
{
|
|
TerminateProcess(j->hProcess, 1067);
|
|
}
|
|
#else
|
|
int code;
|
|
if (j->stdIn != NULL) { j->stdIn->brokenPipeHandler = NULL; }
|
|
if (j->stdOut != NULL) { j->stdOut->brokenPipeHandler = NULL; }
|
|
if (j->stdErr != NULL) { j->stdErr->brokenPipeHandler = NULL; }
|
|
|
|
kill((pid_t)j->PID, SIGKILL);
|
|
waitpid((pid_t)j->PID, &code, 0);
|
|
#endif
|
|
return(j->userObject);
|
|
}
|
|
|
|
ILibProcessPipe_Process ILibProcessPipe_Manager_SpawnProcessEx2(ILibProcessPipe_Manager pipeManager, char* target, char* const* parameters, ILibProcessPipe_SpawnTypes spawnType, int extraMemorySize)
|
|
{
|
|
ILibProcessPipe_Process_Object* retVal = NULL;
|
|
|
|
#ifdef WIN32
|
|
STARTUPINFOA info = { 0 };
|
|
PROCESS_INFORMATION processInfo = { 0 };
|
|
SECURITY_ATTRIBUTES saAttr;
|
|
char* parms = NULL;
|
|
DWORD sessionId;
|
|
HANDLE token=NULL, userToken=NULL, procHandle=NULL;
|
|
int allocParms = 0;
|
|
|
|
ZeroMemory(&processInfo, sizeof(PROCESS_INFORMATION));
|
|
ZeroMemory(&info, sizeof(STARTUPINFOA));
|
|
|
|
if (spawnType != ILibProcessPipe_SpawnTypes_DEFAULT && (sessionId = WTSGetActiveConsoleSessionId()) == 0xFFFFFFFF) { return(NULL); } // No session attached to console, but requested to execute as logged in user
|
|
if (spawnType != ILibProcessPipe_SpawnTypes_DEFAULT)
|
|
{
|
|
procHandle = GetCurrentProcess();
|
|
if (OpenProcessToken(procHandle, TOKEN_DUPLICATE, &token) == 0) { ILIBMARKPOSITION(2); return(NULL); }
|
|
if (DuplicateTokenEx(token, MAXIMUM_ALLOWED, 0, SecurityImpersonation, TokenPrimary, &userToken) == 0) { CloseHandle(token); ILIBMARKPOSITION(2); return(NULL); }
|
|
if (SetTokenInformation(userToken, (TOKEN_INFORMATION_CLASS)TokenSessionId, &sessionId, sizeof(sessionId)) == 0) { CloseHandle(token); CloseHandle(userToken); ILIBMARKPOSITION(2); return(NULL); }
|
|
if (spawnType == ILibProcessPipe_SpawnTypes_WINLOGON) { info.lpDesktop = "Winsta0\\Winlogon"; }
|
|
}
|
|
if (parameters != NULL && parameters[0] != NULL && parameters[1] == NULL)
|
|
{
|
|
parms = parameters[0];
|
|
}
|
|
else if (parameters != NULL && parameters[0] != NULL && parameters[1] != NULL)
|
|
{
|
|
int len = 0;
|
|
int i = 0;
|
|
int sz = 0;
|
|
|
|
while (parameters[i] != NULL)
|
|
{
|
|
sz += ((int)strnlen_s(parameters[i++], _MAX_PATH) + 1);
|
|
}
|
|
sz += (i - 1); // Need to make room for delimiter characters
|
|
parms = (char*)malloc(sz);
|
|
i = 0; len = 0;
|
|
allocParms = 1;
|
|
|
|
while (parameters[i] != NULL)
|
|
{
|
|
len += sprintf_s(parms + len, sz - len, "%s%s", (i==0)?"":" ", parameters[i]);
|
|
++i;
|
|
}
|
|
}
|
|
|
|
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
|
saAttr.bInheritHandle = TRUE;
|
|
saAttr.lpSecurityDescriptor = NULL;
|
|
#else
|
|
pid_t pid;
|
|
#endif
|
|
|
|
if ((retVal = (ILibProcessPipe_Process_Object*)malloc(sizeof(ILibProcessPipe_Process_Object))) == NULL) { ILIBCRITICALEXIT(254); }
|
|
memset(retVal, 0, sizeof(ILibProcessPipe_Process_Object));
|
|
|
|
retVal->stdErr = ILibProcessPipe_CreatePipe(pipeManager, 4096, NULL, extraMemorySize);
|
|
retVal->stdErr->mProcess = retVal;
|
|
retVal->parent = (ILibProcessPipe_Manager_Object*)pipeManager;
|
|
retVal->chain = retVal->parent->ChainLink.ParentChain;
|
|
#ifdef WIN32
|
|
retVal->stdIn = ILibProcessPipe_CreatePipe(pipeManager, 4096, NULL, extraMemorySize);
|
|
retVal->stdIn->mProcess = retVal;
|
|
retVal->stdOut = ILibProcessPipe_CreatePipe(pipeManager, 4096, NULL, extraMemorySize);
|
|
retVal->stdOut->mProcess = retVal;
|
|
|
|
ILibProcessPipe_PipeObject_DisableInherit(&(retVal->stdIn->mPipe_WriteEnd));
|
|
ILibProcessPipe_PipeObject_DisableInherit(&(retVal->stdOut->mPipe_ReadEnd));
|
|
ILibProcessPipe_PipeObject_DisableInherit(&(retVal->stdErr->mPipe_ReadEnd));
|
|
|
|
info.cb = sizeof(STARTUPINFOA);
|
|
info.hStdError = retVal->stdErr->mPipe_WriteEnd;
|
|
info.hStdInput = retVal->stdIn->mPipe_ReadEnd;
|
|
info.hStdOutput = retVal->stdOut->mPipe_WriteEnd;
|
|
info.dwFlags |= STARTF_USESTDHANDLES;
|
|
|
|
if((spawnType == ILibProcessPipe_SpawnTypes_DEFAULT && !CreateProcessA(target, parms, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &info, &processInfo)) ||
|
|
(spawnType != ILibProcessPipe_SpawnTypes_DEFAULT && !CreateProcessAsUserA(userToken, target, parms, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &info, &processInfo)))
|
|
{
|
|
ILibProcessPipe_FreePipe(retVal->stdErr);
|
|
ILibProcessPipe_FreePipe(retVal->stdOut);
|
|
ILibProcessPipe_FreePipe(retVal->stdIn);
|
|
if (allocParms != 0) { free(parms); }
|
|
free(retVal);
|
|
if (token != NULL) { CloseHandle(token); }
|
|
if (userToken != NULL) { CloseHandle(userToken); }
|
|
return(NULL);
|
|
}
|
|
|
|
|
|
if (allocParms != 0) { free(parms); }
|
|
CloseHandle(retVal->stdOut->mPipe_WriteEnd); retVal->stdOut->mPipe_WriteEnd = NULL;
|
|
CloseHandle(retVal->stdErr->mPipe_WriteEnd); retVal->stdErr->mPipe_WriteEnd = NULL;
|
|
CloseHandle(retVal->stdIn->mPipe_ReadEnd); retVal->stdIn->mPipe_ReadEnd = NULL;
|
|
|
|
retVal->hProcess = processInfo.hProcess;
|
|
if (processInfo.hThread != NULL) CloseHandle(processInfo.hThread);
|
|
retVal->PID = processInfo.dwProcessId;
|
|
#else
|
|
if (spawnType == ILibProcessPipe_SpawnTypes_TERM)
|
|
{
|
|
int pipe;
|
|
struct winsize w;
|
|
w.ws_row = CONSOLE_SCREEN_HEIGHT;
|
|
w.ws_col = CONSOLE_SCREEN_WIDTH;
|
|
w.ws_xpixel = 0;
|
|
w.ws_ypixel = 0;
|
|
pid = forkpty(&pipe, NULL, NULL, &w);
|
|
|
|
retVal->stdIn = ILibProcessPipe_Pipe_CreateFromExistingWithExtraMemory(pipeManager, pipe, extraMemorySize);
|
|
retVal->stdIn->mProcess = retVal;
|
|
retVal->stdOut = ILibProcessPipe_Pipe_CreateFromExistingWithExtraMemory(pipeManager, pipe, extraMemorySize);
|
|
ILibProcessPipe_Pipe_SetBrokenPipeHandler(retVal->stdOut, ILibProcessPipe_Process_BrokenPipeSink);
|
|
retVal->stdOut->mProcess = retVal;
|
|
}
|
|
else
|
|
{
|
|
retVal->stdIn = ILibProcessPipe_CreatePipe(pipeManager, 4096, NULL, extraMemorySize);
|
|
retVal->stdIn->mProcess = retVal;
|
|
retVal->stdOut = ILibProcessPipe_CreatePipe(pipeManager, 4096, (ILibProcessPipe_GenericBrokenPipeHandler) ILibProcessPipe_Process_BrokenPipeSink, extraMemorySize);
|
|
retVal->stdOut->mProcess = retVal;
|
|
pid = vfork();
|
|
}
|
|
if(pid < 0)
|
|
{
|
|
ILibProcessPipe_FreePipe(retVal->stdErr);
|
|
ILibProcessPipe_FreePipe(retVal->stdOut);
|
|
ILibProcessPipe_FreePipe(retVal->stdIn);
|
|
free(retVal);
|
|
return(NULL);
|
|
}
|
|
if(pid==0)
|
|
{
|
|
close(retVal->stdErr->mPipe_ReadEnd); //close read end of stderr pipe
|
|
dup2(retVal->stdErr->mPipe_WriteEnd, STDERR_FILENO);
|
|
close(retVal->stdErr->mPipe_WriteEnd);
|
|
|
|
if (spawnType == ILibProcessPipe_SpawnTypes_TERM)
|
|
{
|
|
putenv("TERM=xterm");
|
|
}
|
|
else
|
|
{
|
|
close(retVal->stdIn->mPipe_WriteEnd); //close write end of stdin pipe
|
|
close(retVal->stdOut->mPipe_ReadEnd); //close read end of stdout pipe
|
|
|
|
dup2(retVal->stdIn->mPipe_ReadEnd, STDIN_FILENO);
|
|
dup2(retVal->stdOut->mPipe_WriteEnd, STDOUT_FILENO);
|
|
|
|
close(retVal->stdIn->mPipe_ReadEnd);
|
|
close(retVal->stdOut->mPipe_WriteEnd);
|
|
}
|
|
execv(target, parameters);
|
|
exit(1);
|
|
}
|
|
if (spawnType != ILibProcessPipe_SpawnTypes_TERM)
|
|
{
|
|
close(retVal->stdIn->mPipe_ReadEnd);
|
|
close(retVal->stdOut->mPipe_WriteEnd);
|
|
}
|
|
close(retVal->stdErr->mPipe_WriteEnd);
|
|
retVal->PID = pid;
|
|
#endif
|
|
return retVal;
|
|
}
|
|
void ILibProcessPipe_Pipe_SwapBuffers(ILibProcessPipe_Pipe obj, char* newBuffer, int newBufferLen, int newBufferReadOffset, int newBufferTotalBytesRead, char **oldBuffer, int *oldBufferLen, int *oldBufferReadOffset, int *oldBufferTotalBytesRead)
|
|
{
|
|
ILibProcessPipe_PipeObject *pipeObject = (ILibProcessPipe_PipeObject*)obj;
|
|
|
|
*oldBuffer = pipeObject->buffer;
|
|
if (oldBufferLen != NULL) { *oldBufferLen = pipeObject->bufferSize; }
|
|
if (oldBufferReadOffset != NULL) { *oldBufferReadOffset = pipeObject->readOffset; }
|
|
if (oldBufferTotalBytesRead != NULL) { *oldBufferTotalBytesRead = pipeObject->totalRead; }
|
|
|
|
pipeObject->buffer = newBuffer;
|
|
pipeObject->bufferSize = newBufferLen;
|
|
pipeObject->readOffset = newBufferReadOffset;
|
|
pipeObject->totalRead = newBufferTotalBytesRead;
|
|
}
|
|
#ifdef WIN32
|
|
BOOL ILibProcessPipe_Process_ReadHandler(HANDLE event, void* user)
|
|
#else
|
|
void ILibProcessPipe_Process_ReadHandler(void* user)
|
|
#endif
|
|
{
|
|
ILibProcessPipe_PipeObject *pipeObject = (ILibProcessPipe_PipeObject*)user;
|
|
int consumed;
|
|
int err;
|
|
|
|
#ifdef WIN32
|
|
BOOL result;
|
|
DWORD bytesRead;
|
|
UNREFERENCED_PARAMETER(event);
|
|
#else
|
|
int bytesRead;
|
|
#endif
|
|
pipeObject->processingLoop = 1;
|
|
do
|
|
{
|
|
#ifdef WIN32
|
|
result = GetOverlappedResult(pipeObject->mPipe_ReadEnd, pipeObject->mOverlapped, &bytesRead, FALSE);
|
|
if (result == FALSE) { break; }
|
|
#else
|
|
bytesRead = (int)read(pipeObject->mPipe_ReadEnd, pipeObject->buffer + pipeObject->totalRead, pipeObject->bufferSize - pipeObject->totalRead);
|
|
if(bytesRead <= 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
#endif
|
|
|
|
pipeObject->totalRead += bytesRead;
|
|
ILibRemoteLogging_printf(ILibChainGetLogger(pipeObject->manager->ChainLink.ParentChain), ILibRemoteLogging_Modules_Microstack_Pipe, ILibRemoteLogging_Flags_VerbosityLevel_5, "ILibProcessPipe[ReadHandler]: %u bytes read on Pipe: %p", bytesRead, (void*)pipeObject);
|
|
|
|
if (pipeObject->handler == NULL)
|
|
{
|
|
//
|
|
// Since the user doesn't care about the data, we'll just empty the buffer
|
|
//
|
|
pipeObject->readOffset = 0;
|
|
pipeObject->totalRead = 0;
|
|
continue;
|
|
}
|
|
|
|
while (pipeObject->PAUSED == 0)
|
|
{
|
|
consumed = 0;
|
|
ILibRemoteLogging_printf(ILibChainGetLogger(pipeObject->manager->ChainLink.ParentChain), ILibRemoteLogging_Modules_Microstack_Generic, ILibRemoteLogging_Flags_VerbosityLevel_5, "ProcessPipe: buffer/%p offset/%d totalRead/%d", (void*)pipeObject->buffer, pipeObject->readOffset, pipeObject->totalRead);
|
|
|
|
((ILibProcessPipe_GenericReadHandler)pipeObject->handler)(pipeObject->buffer + pipeObject->readOffset, pipeObject->totalRead - pipeObject->readOffset, &consumed, pipeObject->user1, pipeObject->user2);
|
|
if (consumed == 0)
|
|
{
|
|
//
|
|
// None of the buffer was consumed
|
|
//
|
|
ILibRemoteLogging_printf(ILibChainGetLogger(pipeObject->manager->ChainLink.ParentChain), ILibRemoteLogging_Modules_Microstack_Pipe, ILibRemoteLogging_Flags_VerbosityLevel_5, "ILibProcessPipe[ReadHandler]: No bytes consumed on Pipe: %p", (void*)pipeObject);
|
|
|
|
//
|
|
// We need to move the memory to the start of the buffer, or else we risk running past the end, if we keep reading like this
|
|
//
|
|
memmove_s(pipeObject->buffer, pipeObject->bufferSize, pipeObject->buffer + pipeObject->readOffset, pipeObject->totalRead - pipeObject->readOffset);
|
|
pipeObject->totalRead -= pipeObject->readOffset;
|
|
pipeObject->readOffset = 0;
|
|
|
|
break; // Break out of inner while loop
|
|
}
|
|
else if (consumed == (pipeObject->totalRead - pipeObject->readOffset))
|
|
{
|
|
//
|
|
// Entire Buffer was consumed
|
|
//
|
|
pipeObject->readOffset = 0;
|
|
pipeObject->totalRead = 0;
|
|
|
|
ILibRemoteLogging_printf(ILibChainGetLogger(pipeObject->manager->ChainLink.ParentChain), ILibRemoteLogging_Modules_Microstack_Pipe, ILibRemoteLogging_Flags_VerbosityLevel_5, "ILibProcessPipe[ReadHandler]: ReadBuffer drained on Pipe: %p", (void*)pipeObject);
|
|
break; // Break out of inner while loop
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Only part of the buffer was consumed
|
|
//
|
|
pipeObject->readOffset += consumed;
|
|
}
|
|
}
|
|
if (pipeObject->PAUSED != 0) { break; }
|
|
}
|
|
#ifdef WIN32
|
|
while ((result = ReadFile(pipeObject->mPipe_ReadEnd, pipeObject->buffer, pipeObject->bufferSize, NULL, pipeObject->mOverlapped)) == TRUE); // Note: This is actually the end of a do-while loop
|
|
if (pipeObject->PAUSED == 0 && (err = GetLastError()) != ERROR_IO_PENDING)
|
|
#else
|
|
while(pipeObject->PAUSED == 0); // Note: This is actually the end of a do-while loop
|
|
err = 0;
|
|
if(bytesRead == 0 || ((err = errno) != EAGAIN && errno != EWOULDBLOCK && pipeObject->PAUSED == 0))
|
|
#endif
|
|
{
|
|
//
|
|
// Broken Pipe
|
|
//
|
|
ILibRemoteLogging_printf(ILibChainGetLogger(pipeObject->manager->ChainLink.ParentChain), ILibRemoteLogging_Modules_Microstack_Pipe, ILibRemoteLogging_Flags_VerbosityLevel_1, "ILibProcessPipe[ReadHandler]: BrokenPipe(%d) on Pipe: %p", err, (void*)pipeObject);
|
|
#ifdef WIN32
|
|
ILibProcessPipe_WaitHandle_Remove(pipeObject->manager, pipeObject->mOverlapped->hEvent); // Pipe Broken, so remove ourselves from the processing loop
|
|
#else
|
|
// Sincc we are on the microstack thread, we can directly access the LinkedList
|
|
|
|
#endif
|
|
ILibLinkedList_Remove(ILibLinkedList_GetNode_Search(pipeObject->manager->ActivePipes, NULL, pipeObject));
|
|
if (pipeObject->brokenPipeHandler != NULL)
|
|
{
|
|
((ILibProcessPipe_GenericBrokenPipeHandler)pipeObject->brokenPipeHandler)(pipeObject);
|
|
}
|
|
#ifdef WIN32
|
|
return(FALSE);
|
|
#else
|
|
return;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
ILibRemoteLogging_printf(ILibChainGetLogger(pipeObject->manager->ChainLink.ParentChain), ILibRemoteLogging_Modules_Microstack_Pipe, ILibRemoteLogging_Flags_VerbosityLevel_5, "ILibProcessPipe[ReadHandler]: Pipe: %p [EMPTY]", (void*)pipeObject);
|
|
}
|
|
pipeObject->processingLoop = 0;
|
|
ILibRemoteLogging_printf(ILibChainGetLogger(pipeObject->manager->ChainLink.ParentChain), ILibRemoteLogging_Modules_Microstack_Generic, ILibRemoteLogging_Flags_VerbosityLevel_1, "ILibProcessPipe[ReadHandler]: Pipe: %p [EMPTY]", (void*)pipeObject);
|
|
|
|
#ifdef WIN32
|
|
return(TRUE);
|
|
#else
|
|
return;
|
|
#endif
|
|
}
|
|
#ifdef WIN32
|
|
BOOL ILibProcessPipe_Process_WindowsWriteHandler(HANDLE event, void* user)
|
|
{
|
|
ILibProcessPipe_PipeObject *pipeObject = (ILibProcessPipe_PipeObject*)user;
|
|
BOOL result;
|
|
DWORD bytesWritten;
|
|
ILibProcessPipe_WriteData* data;
|
|
|
|
UNREFERENCED_PARAMETER(event);
|
|
result = GetOverlappedResult(pipeObject->mPipe_WriteEnd, pipeObject->mOverlapped, &bytesWritten, FALSE);
|
|
if (result == FALSE)
|
|
{
|
|
// Broken Pipe
|
|
ILibProcessPipe_WaitHandle_Remove(pipeObject->manager, pipeObject->mOverlapped->hEvent); // Pipe Broken, so remove ourselves from the processing loop
|
|
ILibRemoteLogging_printf(ILibChainGetLogger(pipeObject->manager->ChainLink.ParentChain), ILibRemoteLogging_Modules_Microstack_Pipe, ILibRemoteLogging_Flags_VerbosityLevel_1, "ILibProcessPipe[WriteHandler]: BrokenPipe(%d) on Pipe: %p", GetLastError(), (void*)pipeObject);
|
|
if (pipeObject->brokenPipeHandler != NULL) { ((ILibProcessPipe_GenericBrokenPipeHandler)pipeObject->brokenPipeHandler)(pipeObject); }
|
|
ILibProcessPipe_FreePipe(pipeObject);
|
|
return(FALSE);
|
|
}
|
|
|
|
ILibQueue_Lock(pipeObject->WriteBuffer);
|
|
while ((data = (ILibProcessPipe_WriteData*)ILibQueue_DeQueue(pipeObject->WriteBuffer)) != NULL)
|
|
{
|
|
ILibProcessPipe_WriteData_Destroy(data);
|
|
data = (ILibProcessPipe_WriteData*)ILibQueue_PeekQueue(pipeObject->WriteBuffer);
|
|
if (data != NULL)
|
|
{
|
|
result = WriteFile(pipeObject->mPipe_WriteEnd, data->buffer, data->bufferLen, NULL, pipeObject->mOverlapped);
|
|
if (result == TRUE) { continue; }
|
|
if (GetLastError() != ERROR_IO_PENDING)
|
|
{
|
|
// Broken Pipe
|
|
ILibQueue_UnLock(pipeObject->WriteBuffer);
|
|
ILibRemoteLogging_printf(ILibChainGetLogger(pipeObject->manager->ChainLink.ParentChain), ILibRemoteLogging_Modules_Microstack_Pipe, ILibRemoteLogging_Flags_VerbosityLevel_1, "ILibProcessPipe[WriteHandler]: BrokenPipe(%d) on Pipe: %p", GetLastError(), (void*)pipeObject);
|
|
if (pipeObject->brokenPipeHandler != NULL) { ((ILibProcessPipe_GenericBrokenPipeHandler)pipeObject->brokenPipeHandler)(pipeObject); }
|
|
ILibProcessPipe_FreePipe(pipeObject);
|
|
return(FALSE);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
if (ILibQueue_IsEmpty(pipeObject->WriteBuffer) != 0)
|
|
{
|
|
ILibProcessPipe_WaitHandle_Remove(pipeObject->manager, pipeObject->mOverlapped->hEvent);
|
|
ILibQueue_UnLock(pipeObject->WriteBuffer);
|
|
if (pipeObject->handler != NULL) ((ILibProcessPipe_GenericSendOKHandler)pipeObject->handler)(pipeObject->user1, pipeObject->user2);
|
|
}
|
|
else
|
|
{
|
|
ILibQueue_UnLock(pipeObject->WriteBuffer);
|
|
}
|
|
return(TRUE);
|
|
}
|
|
#endif
|
|
void ILibProcessPipe_Process_SetWriteHandler(ILibProcessPipe_PipeObject *pipeObject, ILibProcessPipe_GenericSendOKHandler handler, void* user1, void* user2)
|
|
{
|
|
pipeObject->handler = (void*)handler;
|
|
pipeObject->user1 = user1;
|
|
pipeObject->user2 = user2;
|
|
}
|
|
|
|
void ILibProcessPipe_Process_StartPipeReaderWriterEx(void *object)
|
|
{
|
|
ILibProcessPipe_PipeObject* pipeObject = (ILibProcessPipe_PipeObject*)object;
|
|
ILibLinkedList_AddTail(pipeObject->manager->ActivePipes, pipeObject);
|
|
}
|
|
|
|
void ILibProcessPipe_Pipe_Pause(ILibProcessPipe_Pipe pipeObject)
|
|
{
|
|
ILibProcessPipe_PipeObject *p = (ILibProcessPipe_PipeObject*)pipeObject;
|
|
p->PAUSED = 1;
|
|
|
|
#ifdef WIN32
|
|
if (p->mOverlapped == NULL)
|
|
{
|
|
// Overlapped isn't supported, so using a separate reader thread
|
|
ResetEvent(p->mPipe_Reader_ResumeEvent);
|
|
}
|
|
else
|
|
{
|
|
ILibRemoteLogging_printf(ILibChainGetLogger(p->manager->ChainLink.ParentChain), ILibRemoteLogging_Modules_Microstack_Generic, ILibRemoteLogging_Flags_VerbosityLevel_1, "ProcessPipe.Pause(): Opaque = %p",(void*)p->mOverlapped_opaqueData);
|
|
if (p->manager->workerThreadID == GetCurrentThreadId())
|
|
{
|
|
// Already on the dispatch thread, so we can directly update the list
|
|
if (p->mOverlapped_opaqueData == NULL)
|
|
{
|
|
void *node = ILibLinkedList_GetNode_Search(p->manager->ActivePipes, NULL, p->manager->activeWaitHandle);
|
|
if (node != NULL)
|
|
{
|
|
ILibLinkedList_Remove(node);
|
|
p->mOverlapped_opaqueData = p->manager->activeWaitHandle;
|
|
ILibRemoteLogging_printf(ILibChainGetLogger(p->manager->ChainLink.ParentChain), ILibRemoteLogging_Modules_Microstack_Generic, ILibRemoteLogging_Flags_VerbosityLevel_1, "...Opaque = %p", (void*)p->mOverlapped_opaqueData);
|
|
SetEvent(p->manager->updateEvent); // Just need to set event, so the wait list will be rebuilt
|
|
}
|
|
else
|
|
{
|
|
ILibRemoteLogging_printf(ILibChainGetLogger(p->manager->ChainLink.ParentChain), ILibRemoteLogging_Modules_Microstack_Generic, ILibRemoteLogging_Flags_VerbosityLevel_1, "ProcessPipe.Pause(): Active pipe not in list");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ILibRemoteLogging_printf(ILibChainGetLogger(p->manager->ChainLink.ParentChain), ILibRemoteLogging_Modules_Microstack_Generic, ILibRemoteLogging_Flags_VerbosityLevel_1, "ProcessPipe.Pause(): Already paused");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Not on the dispatch thread, so we'll have to dispatch
|
|
p->mOverlapped_opaqueData = NULL;
|
|
ILibProcessPipe_WaitHandle_Remove(p->manager, p->mOverlapped->hEvent);
|
|
}
|
|
|
|
//if (p->mOverlapped_opaqueData == NULL)
|
|
//{
|
|
// void *node = ILibLinkedList_GetNode_Search(p->manager->ActivePipes, NULL, p->manager->activeWaitHandle);
|
|
// if (node != NULL)
|
|
// {
|
|
// ILibLinkedList_Remove(node);
|
|
// p->mOverlapped_opaqueData = p->manager->activeWaitHandle;
|
|
// ILibRemoteLogging_printf(ILibChainGetLogger(p->manager->ChainLink.ParentChain), ILibRemoteLogging_Modules_Microstack_Generic, ILibRemoteLogging_Flags_VerbosityLevel_1, "...Opaque = %p", (void*)p->mOverlapped_opaqueData);
|
|
// SetEvent(p->manager->updateEvent);
|
|
// }
|
|
// else
|
|
// {
|
|
// ILibRemoteLogging_printf(ILibChainGetLogger(p->manager->ChainLink.ParentChain), ILibRemoteLogging_Modules_Microstack_Generic, ILibRemoteLogging_Flags_VerbosityLevel_1, "ProcessPipe.Pause(): Active pipe not in list");
|
|
// }
|
|
//}
|
|
}
|
|
#else
|
|
ILibLinkedList_Remove(ILibLinkedList_GetNode_Search(p->manager->ActivePipes, NULL, pipeObject));
|
|
#endif
|
|
}
|
|
|
|
|
|
void ILibProcessPipe_Pipe_ResumeEx_ContinueProcessing(ILibProcessPipe_PipeObject *p)
|
|
{
|
|
int consumed;
|
|
p->PAUSED = 0;
|
|
p->processingLoop = 1;
|
|
while (p->readOffset != 0 && p->PAUSED == 0)
|
|
{
|
|
consumed = 0;
|
|
((ILibProcessPipe_GenericReadHandler)p->handler)(p->buffer + p->readOffset, p->totalRead - p->readOffset, &consumed, p->user1, p->user2);
|
|
if (consumed == 0)
|
|
{
|
|
//
|
|
// None of the buffer was consumed
|
|
//
|
|
ILibRemoteLogging_printf(ILibChainGetLogger(p->manager->ChainLink.ParentChain), ILibRemoteLogging_Modules_Microstack_Pipe, ILibRemoteLogging_Flags_VerbosityLevel_5, "ILibProcessPipe[ReadHandler]: No bytes consumed on Pipe: %p", (void*)p);
|
|
|
|
//
|
|
// We need to move the memory to the start of the buffer, or else we risk running past the end, if we keep reading like this
|
|
//
|
|
memmove_s(p->buffer, p->bufferSize, p->buffer + p->readOffset, p->totalRead - p->readOffset);
|
|
p->totalRead -= p->readOffset;
|
|
p->readOffset = 0;
|
|
}
|
|
else if (consumed == (p->totalRead - p->readOffset))
|
|
{
|
|
//
|
|
// Entire Buffer was consumed
|
|
//
|
|
p->readOffset = 0;
|
|
p->totalRead = 0;
|
|
|
|
ILibRemoteLogging_printf(ILibChainGetLogger(p->manager->ChainLink.ParentChain), ILibRemoteLogging_Modules_Microstack_Pipe, ILibRemoteLogging_Flags_VerbosityLevel_5, "ILibProcessPipe[ReadHandler]: ReadBuffer drained on Pipe: %p", (void*)p);
|
|
break; // Break out of inner while loop
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Only part of the buffer was consumed
|
|
//
|
|
p->readOffset += consumed;
|
|
}
|
|
}
|
|
p->processingLoop = 0;
|
|
}
|
|
#ifdef WIN32
|
|
void __stdcall ILibProcessPipe_Pipe_ResumeEx_APC(ULONG_PTR obj)
|
|
{
|
|
ILibProcessPipe_PipeObject *p = (ILibProcessPipe_PipeObject*)obj;
|
|
|
|
ILibProcessPipe_Pipe_ResumeEx_ContinueProcessing(p);
|
|
|
|
if (p->PAUSED == 0)
|
|
{
|
|
ILibRemoteLogging_printf(ILibChainGetLogger(p->manager->ChainLink.ParentChain), ILibRemoteLogging_Modules_Microstack_Generic, ILibRemoteLogging_Flags_VerbosityLevel_1, "ProcessPipe.ResumeEx_APC(): Adding Pipe [%p]", (void*)p);
|
|
if (p->mOverlapped_opaqueData != NULL)
|
|
{
|
|
ILibProcessPipe_WaitHandle_AddEx(p->manager, (ILibProcessPipe_WaitHandle*)p->mOverlapped_opaqueData);
|
|
p->mOverlapped_opaqueData = NULL;
|
|
}
|
|
else
|
|
{
|
|
ILibProcessPipe_WaitHandle_Add(p->manager, p->mOverlapped->hEvent, p, ILibProcessPipe_Process_ReadHandler);
|
|
}
|
|
ReadFile(p->mPipe_ReadEnd, p->buffer, p->bufferSize, NULL, p->mOverlapped);
|
|
}
|
|
else
|
|
{
|
|
ILibRemoteLogging_printf(ILibChainGetLogger(p->manager->ChainLink.ParentChain), ILibRemoteLogging_Modules_Microstack_Generic, ILibRemoteLogging_Flags_VerbosityLevel_1, "ProcessPipe.ResumeEx_APC(): Skipping Pipe [%p]", (void*)p);
|
|
}
|
|
}
|
|
#endif
|
|
void ILibProcessPipe_Pipe_ResumeEx(ILibProcessPipe_PipeObject* p)
|
|
{
|
|
ILibRemoteLogging_printf(ILibChainGetLogger(p->manager->ChainLink.ParentChain), ILibRemoteLogging_Modules_Microstack_Generic, ILibRemoteLogging_Flags_VerbosityLevel_1, "ProcessPipe.ResumeEx(): processingLoop = %d", p->processingLoop);
|
|
|
|
#ifdef WIN32
|
|
if (p->manager->workerThreadID == GetCurrentThreadId())
|
|
{
|
|
// We were called from the event dispatch (ie: we're on the same thread)
|
|
if (p->mOverlapped_opaqueData != NULL)
|
|
{
|
|
ILibProcessPipe_WaitHandle_AddEx(p->manager, (ILibProcessPipe_WaitHandle*)p->mOverlapped_opaqueData);
|
|
p->mOverlapped_opaqueData = NULL;
|
|
}
|
|
else
|
|
{
|
|
ILibProcessPipe_WaitHandle_Add(p->manager, p->mOverlapped->hEvent, p, ILibProcessPipe_Process_ReadHandler);
|
|
}
|
|
p->PAUSED = 0;
|
|
}
|
|
else
|
|
{
|
|
// We're on a different thread, so we need to dispatch to the worker thread
|
|
QueueUserAPC((PAPCFUNC)ILibProcessPipe_Pipe_ResumeEx_APC, p->manager->workerThread, (ULONG_PTR)p);
|
|
}
|
|
return;
|
|
#endif
|
|
|
|
ILibProcessPipe_Pipe_ResumeEx_ContinueProcessing(p);
|
|
if (p->PAUSED == 0)
|
|
{
|
|
ILibLifeTime_Add(ILibGetBaseTimer(p->manager->ChainLink.ParentChain), p, 0, &ILibProcessPipe_Process_StartPipeReaderWriterEx, NULL); // Need to context switch to Chain Thread
|
|
}
|
|
}
|
|
void ILibProcessPipe_Pipe_Resume(ILibProcessPipe_Pipe pipeObject)
|
|
{
|
|
ILibProcessPipe_PipeObject *p = (ILibProcessPipe_PipeObject*)pipeObject;
|
|
#ifdef WIN32
|
|
if (p->mOverlapped == NULL)
|
|
{
|
|
SetEvent(p->mPipe_Reader_ResumeEvent);
|
|
}
|
|
else
|
|
{
|
|
ILibProcessPipe_Pipe_ResumeEx(p);
|
|
if (p->mProcess != NULL && p->mProcess->hProcess_needAdd != 0)
|
|
{
|
|
p->mProcess->hProcess_needAdd = 0;
|
|
ILibProcessPipe_WaitHandle_Add(p->manager, p->mProcess->hProcess, p->mProcess, ILibProcessPipe_Process_OnExit);
|
|
}
|
|
}
|
|
#else
|
|
ILibProcessPipe_Pipe_ResumeEx(p);
|
|
#endif
|
|
}
|
|
|
|
#ifdef WIN32
|
|
DWORD ILibProcessPipe_Pipe_BackgroundReader(void *arg)
|
|
{
|
|
ILibProcessPipe_PipeObject *pipeObject = (ILibProcessPipe_PipeObject*)arg;
|
|
DWORD bytesRead = 0;
|
|
int consumed;
|
|
|
|
while (pipeObject->PAUSED == 0 || WaitForSingleObject(pipeObject->mPipe_Reader_ResumeEvent, INFINITE) == WAIT_OBJECT_0)
|
|
{
|
|
// Pipe is in ACTIVE state
|
|
consumed = 0;
|
|
pipeObject->PAUSED = 0;
|
|
|
|
while (pipeObject->readOffset != 0 && pipeObject->PAUSED == 0)
|
|
{
|
|
((ILibProcessPipe_GenericReadHandler)pipeObject->handler)(pipeObject->buffer + pipeObject->readOffset, pipeObject->totalRead - pipeObject->readOffset, &consumed, pipeObject->user1, pipeObject->user2);
|
|
if (consumed == 0)
|
|
{
|
|
memmove_s(pipeObject->buffer, pipeObject->bufferSize, pipeObject->buffer + pipeObject->readOffset, pipeObject->totalRead - pipeObject->readOffset);
|
|
pipeObject->totalRead -= pipeObject->readOffset;
|
|
pipeObject->readOffset = 0;
|
|
}
|
|
else if (consumed == (pipeObject->totalRead - pipeObject->readOffset))
|
|
{
|
|
// Entire buffer consumed
|
|
pipeObject->readOffset = 0;
|
|
pipeObject->totalRead = 0;
|
|
consumed = 0;
|
|
}
|
|
else
|
|
{
|
|
// Partial Consumed
|
|
pipeObject->readOffset += consumed;
|
|
}
|
|
}
|
|
|
|
if (pipeObject->PAUSED == 1) { continue; }
|
|
if (!ReadFile(pipeObject->mPipe_ReadEnd, pipeObject->buffer + pipeObject->readOffset, pipeObject->bufferSize - pipeObject->readOffset, &bytesRead, NULL)) { break; }
|
|
|
|
consumed = 0;
|
|
pipeObject->totalRead += bytesRead;
|
|
((ILibProcessPipe_GenericReadHandler)pipeObject->handler)(pipeObject->buffer + pipeObject->readOffset, pipeObject->totalRead - pipeObject->readOffset, &consumed, pipeObject->user1, pipeObject->user2);
|
|
pipeObject->readOffset += consumed;
|
|
}
|
|
|
|
if (pipeObject->brokenPipeHandler != NULL) { pipeObject->brokenPipeHandler(pipeObject); }
|
|
ILibProcessPipe_FreePipe(pipeObject);
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
void ILibProcessPipe_Process_StartPipeReader(ILibProcessPipe_PipeObject *pipeObject, int bufferSize, ILibProcessPipe_GenericReadHandler handler, void* user1, void* user2)
|
|
{
|
|
#ifdef WIN32
|
|
BOOL result;
|
|
#endif
|
|
|
|
if ((pipeObject->buffer = (char*)malloc(bufferSize)) == NULL) { ILIBCRITICALEXIT(254); }
|
|
pipeObject->bufferSize = bufferSize;
|
|
pipeObject->handler = (void*)handler;
|
|
pipeObject->user1 = user1;
|
|
pipeObject->user2 = user2;
|
|
|
|
#ifdef WIN32
|
|
if (pipeObject->mOverlapped != NULL)
|
|
{
|
|
// This PIPE supports Overlapped I/O
|
|
result = ReadFile(pipeObject->mPipe_ReadEnd, pipeObject->buffer, pipeObject->bufferSize, NULL, pipeObject->mOverlapped);
|
|
ILibProcessPipe_WaitHandle_Add(pipeObject->manager, pipeObject->mOverlapped->hEvent, pipeObject, &ILibProcessPipe_Process_ReadHandler);
|
|
}
|
|
else
|
|
{
|
|
// This PIPE does NOT support overlapped I/O, so we have to fake it with a background thread
|
|
pipeObject->mPipe_Reader_ResumeEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
|
|
ILibSpawnNormalThread(&ILibProcessPipe_Pipe_BackgroundReader, pipeObject);
|
|
}
|
|
#else
|
|
ILibLifeTime_Add(ILibGetBaseTimer(pipeObject->manager->ChainLink.ParentChain), pipeObject, 0, &ILibProcessPipe_Process_StartPipeReaderWriterEx, NULL); // Need to context switch to Chain Thread
|
|
#endif
|
|
}
|
|
void ILibProcessPipe_Process_PipeHandler_StdOut(char *buffer, int bufferLen, int* bytesConsumed, void* user1, void *user2)
|
|
{
|
|
ILibProcessPipe_Process_Object *j = (ILibProcessPipe_Process_Object*)user1;
|
|
if (user2 != NULL)
|
|
{
|
|
((ILibProcessPipe_Process_OutputHandler)user2)(j, buffer, bufferLen, bytesConsumed, j->userObject);
|
|
}
|
|
}
|
|
void ILibProcessPipe_Process_PipeHandler_StdIn(void *user1, void *user2)
|
|
{
|
|
ILibProcessPipe_Process_Object* j = (ILibProcessPipe_Process_Object*)user1;
|
|
ILibProcessPipe_Process_SendOKHandler sendOk = (ILibProcessPipe_Process_SendOKHandler)user2;
|
|
|
|
if (sendOk != NULL) sendOk(j, j->userObject);
|
|
}
|
|
|
|
#ifdef WIN32
|
|
void __stdcall ILibProcessPipe_Process_OnExit_ChainSink_DestroySink(ULONG_PTR obj)
|
|
{
|
|
ILibProcessPipe_Process_Object* j = (ILibProcessPipe_Process_Object*)obj;
|
|
if (j->exiting == 0) { ILibProcessPipe_Process_Destroy(j); }
|
|
}
|
|
void ILibProcessPipe_Process_OnExit_ChainSink(void *chain, void *user)
|
|
{
|
|
ILibProcessPipe_Process_Object* j = (ILibProcessPipe_Process_Object*)user;
|
|
DWORD exitCode;
|
|
BOOL result;
|
|
|
|
result = GetExitCodeProcess(j->hProcess, &exitCode);
|
|
j->exiting = 1;
|
|
j->exitHandler(j, exitCode, j->userObject);
|
|
j->exiting ^= 1;
|
|
|
|
// We can't destroy this now, because we're on the MicrostackThread. We must destroy this on the WindowsRunLoop Thread.
|
|
QueueUserAPC((PAPCFUNC)ILibProcessPipe_Process_OnExit_ChainSink_DestroySink, j->parent->workerThread, (ULONG_PTR)j);
|
|
}
|
|
BOOL ILibProcessPipe_Process_OnExit(HANDLE event, void* user)
|
|
{
|
|
ILibProcessPipe_Process_Object* j = (ILibProcessPipe_Process_Object*)user;
|
|
|
|
UNREFERENCED_PARAMETER(event);
|
|
ILibProcessPipe_WaitHandle_Remove(j->parent, j->hProcess);
|
|
if (j->stdOut->PAUSED != 0 || j->stdErr->PAUSED != 0)
|
|
{
|
|
j->hProcess_needAdd = 1;
|
|
}
|
|
else
|
|
{
|
|
if (j->exitHandler != NULL)
|
|
{
|
|
// Everyone's lifes is made easier, by context switching to chain thread before making this call
|
|
ILibChain_RunOnMicrostackThread(j->parent->ChainLink.ParentChain, ILibProcessPipe_Process_OnExit_ChainSink, user);
|
|
}
|
|
else
|
|
{
|
|
ILibProcessPipe_Process_Destroy(j);
|
|
}
|
|
}
|
|
return(FALSE);
|
|
}
|
|
#endif
|
|
void ILibProcessPipe_Process_UpdateUserObject(ILibProcessPipe_Process module, void *userObj)
|
|
{
|
|
((ILibProcessPipe_Process_Object*)module)->userObject = userObj;
|
|
}
|
|
void ILibProcessPipe_Process_AddHandlers(ILibProcessPipe_Process module, int bufferSize, ILibProcessPipe_Process_ExitHandler exitHandler, ILibProcessPipe_Process_OutputHandler stdOut, ILibProcessPipe_Process_OutputHandler stdErr, ILibProcessPipe_Process_SendOKHandler sendOk, void *user)
|
|
{
|
|
ILibProcessPipe_Process_Object* j = (ILibProcessPipe_Process_Object*)module;
|
|
j->userObject = user;
|
|
j->exitHandler = exitHandler;
|
|
|
|
ILibProcessPipe_Process_StartPipeReader(j->stdOut, bufferSize, &ILibProcessPipe_Process_PipeHandler_StdOut, j, stdOut);
|
|
ILibProcessPipe_Process_StartPipeReader(j->stdErr, bufferSize, &ILibProcessPipe_Process_PipeHandler_StdOut, j, stdErr);
|
|
ILibProcessPipe_Process_SetWriteHandler(j->stdIn, &ILibProcessPipe_Process_PipeHandler_StdIn, j, sendOk);
|
|
|
|
#ifdef WIN32
|
|
ILibProcessPipe_WaitHandle_Add(j->parent, j->hProcess, j, &ILibProcessPipe_Process_OnExit);
|
|
#endif
|
|
}
|
|
|
|
ILibTransport_DoneState ILibProcessPipe_Pipe_Write(ILibProcessPipe_Pipe po, char* buffer, int bufferLen, ILibTransport_MemoryOwnership ownership)
|
|
{
|
|
ILibProcessPipe_PipeObject* pipeObject = (ILibProcessPipe_PipeObject*)po;
|
|
ILibTransport_DoneState retVal = ILibTransport_DoneState_ERROR;
|
|
|
|
if (pipeObject->WriteBuffer == NULL)
|
|
{
|
|
pipeObject->WriteBuffer = ILibQueue_Create();
|
|
}
|
|
|
|
ILibQueue_Lock(pipeObject->WriteBuffer);
|
|
if (ILibQueue_IsEmpty(pipeObject->WriteBuffer) == 0)
|
|
{
|
|
ILibQueue_EnQueue(pipeObject->WriteBuffer, ILibProcessPipe_WriteData_Create(buffer, bufferLen, ownership));
|
|
}
|
|
else
|
|
{
|
|
#ifdef WIN32
|
|
BOOL result = WriteFile(pipeObject->mPipe_WriteEnd, buffer, bufferLen, NULL, pipeObject->mOverlapped);
|
|
if (result == TRUE) { retVal = ILibTransport_DoneState_COMPLETE; }
|
|
#else
|
|
int result = (int)write(pipeObject->mPipe_WriteEnd, buffer, bufferLen);
|
|
if (result > 0) { retVal = ILibTransport_DoneState_COMPLETE; }
|
|
#endif
|
|
else
|
|
{
|
|
#ifdef WIN32
|
|
if (GetLastError() == ERROR_IO_PENDING)
|
|
#else
|
|
if (result < 0 && (errno == EAGAIN || errno == EWOULDBLOCK))
|
|
#endif
|
|
{
|
|
retVal = ILibTransport_DoneState_INCOMPLETE;
|
|
ILibQueue_EnQueue(pipeObject->WriteBuffer, ILibProcessPipe_WriteData_Create(buffer, bufferLen, ownership));
|
|
#ifdef WIN32
|
|
ILibProcessPipe_WaitHandle_Add(pipeObject->manager, pipeObject->mOverlapped->hEvent, pipeObject, &ILibProcessPipe_Process_WindowsWriteHandler);
|
|
#else
|
|
ILibLifeTime_Add(ILibGetBaseTimer(pipeObject->manager->ChainLink.ParentChain), pipeObject, 0, &ILibProcessPipe_Process_StartPipeReaderWriterEx, NULL); // Need to context switch to Chain Thread
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#ifdef WIN32
|
|
ILibRemoteLogging_printf(ILibChainGetLogger(pipeObject->manager->ChainLink.ParentChain), ILibRemoteLogging_Modules_Microstack_Pipe, ILibRemoteLogging_Flags_VerbosityLevel_1, "ILibProcessPipe[Write]: BrokenPipe(%d) on Pipe: %p", GetLastError(), (void*)pipeObject);
|
|
#else
|
|
ILibRemoteLogging_printf(ILibChainGetLogger(pipeObject->manager->ChainLink.ParentChain), ILibRemoteLogging_Modules_Microstack_Pipe, ILibRemoteLogging_Flags_VerbosityLevel_1, "ILibProcessPipe[Write]: BrokenPipe(%d) on Pipe: %p", result < 0 ? errno : 0, (void*)pipeObject);
|
|
#endif
|
|
ILibQueue_UnLock(pipeObject->WriteBuffer);
|
|
if (pipeObject->brokenPipeHandler != NULL)
|
|
{
|
|
#ifdef WIN32
|
|
ILibProcessPipe_WaitHandle_Remove(pipeObject->manager, pipeObject->mOverlapped->hEvent); // Pipe Broken, so remove ourselves from the processing loop
|
|
#endif
|
|
((ILibProcessPipe_GenericBrokenPipeHandler)pipeObject->brokenPipeHandler)(pipeObject);
|
|
}
|
|
ILibProcessPipe_FreePipe(pipeObject);
|
|
return(ILibTransport_DoneState_ERROR);
|
|
}
|
|
}
|
|
}
|
|
ILibQueue_UnLock(pipeObject->WriteBuffer);
|
|
|
|
return retVal;
|
|
}
|
|
|
|
ILibTransport_DoneState ILibProcessPipe_Process_WriteStdIn(ILibProcessPipe_Process p, char* buffer, int bufferLen, ILibTransport_MemoryOwnership ownership)
|
|
{
|
|
ILibProcessPipe_Process_Object *j = (ILibProcessPipe_Process_Object*)p;
|
|
|
|
return(ILibProcessPipe_Pipe_Write(j->stdIn, buffer, bufferLen, ownership));
|
|
}
|
|
|
|
void ILibProcessPipe_Pipe_ReadSink(char *buffer, int bufferLen, int* bytesConsumed, void* user1, void* user2)
|
|
{
|
|
ILibProcessPipe_Pipe target = (ILibProcessPipe_Pipe)user1;
|
|
|
|
if (user2 != NULL) { ((ILibProcessPipe_Pipe_ReadHandler)user2)(target, buffer, bufferLen, bytesConsumed); }
|
|
}
|
|
void ILibProcessPipe_Pipe_AddPipeReadHandler(ILibProcessPipe_Pipe targetPipe, int bufferSize, ILibProcessPipe_Pipe_ReadHandler OnReadHandler)
|
|
{
|
|
ILibProcessPipe_Process_StartPipeReader(targetPipe, bufferSize, &ILibProcessPipe_Pipe_ReadSink, targetPipe, OnReadHandler);
|
|
}
|
|
#ifdef WIN32
|
|
DWORD ILibProcessPipe_Process_GetPID(ILibProcessPipe_Process p) { return(p != NULL ? (DWORD)((ILibProcessPipe_Process_Object*)p)->PID : 0); }
|
|
#else
|
|
pid_t ILibProcessPipe_Process_GetPID(ILibProcessPipe_Process p) { return(p != NULL ? (pid_t)((ILibProcessPipe_Process_Object*)p)->PID : 0); }
|
|
#endif
|
|
|