1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2025-07-13 01:00:23 +02:00

Add IoHandleRead and IoHandleWrite objects.

General i/o objects for reading and writing file descriptors, in particular those that can block.  In other words, these are not generally to be used with file descriptors for actual files, but rather pipes, sockets, etc.
This commit is contained in:
David Steele
2019-01-17 22:08:31 +02:00
parent bf0c41d9d6
commit ecd56105e6
8 changed files with 479 additions and 8 deletions

View File

@ -29,6 +29,10 @@
</release-improvement-list> </release-improvement-list>
<release-development-list> <release-development-list>
<release-item>
<p>Add <code>IoHandleRead</code> and <code>IoHandleWrite</code> objects.</p>
</release-item>
<release-item> <release-item>
<p>Ignore <id>SIGPIPE</id> signals and check <id>EPIPE</id> result instead.</p> <p>Ignore <id>SIGPIPE</id> signals and check <id>EPIPE</id> result instead.</p>
</release-item> </release-item>

View File

@ -77,6 +77,7 @@ SRCS = \
common/io/filter/filter.c \ common/io/filter/filter.c \
common/io/filter/group.c \ common/io/filter/group.c \
common/io/filter/size.c \ common/io/filter/size.c \
common/io/handleRead.c \
common/io/handleWrite.c \ common/io/handleWrite.c \
common/io/http/client.c \ common/io/http/client.c \
common/io/http/common.c \ common/io/http/common.c \
@ -183,7 +184,7 @@ command/command.o: command/command.c common/assert.h common/debug.h common/error
command/control/control.o: command/control/control.c command/control/control.h common/debug.h common/error.auto.h common/error.h common/io/filter/filter.h common/io/filter/group.h common/io/read.h common/io/write.h common/lock.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h config/config.auto.h config/config.h config/define.auto.h config/define.h storage/fileRead.h storage/fileWrite.h storage/helper.h storage/info.h storage/storage.h command/control/control.o: command/control/control.c command/control/control.h common/debug.h common/error.auto.h common/error.h common/io/filter/filter.h common/io/filter/group.h common/io/read.h common/io/write.h common/lock.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h config/config.auto.h config/config.h config/define.auto.h config/define.h storage/fileRead.h storage/fileWrite.h storage/helper.h storage/info.h storage/storage.h
$(CC) $(CFLAGS) -c command/control/control.c -o command/control/control.o $(CC) $(CFLAGS) -c command/control/control.c -o command/control/control.o
command/help/help.o: command/help/help.c common/assert.h common/debug.h common/error.auto.h common/error.h common/io/handleWrite.h common/lock.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h config/config.auto.h config/config.h config/define.auto.h config/define.h version.h command/help/help.o: command/help/help.c common/assert.h common/debug.h common/error.auto.h common/error.h common/io/filter/filter.h common/io/filter/group.h common/io/handleWrite.h common/io/write.h common/lock.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h config/config.auto.h config/config.h config/define.auto.h config/define.h version.h
$(CC) $(CFLAGS) -c command/help/help.c -o command/help/help.o $(CC) $(CFLAGS) -c command/help/help.c -o command/help/help.o
command/info/info.o: command/info/info.c command/archive/common.h command/info/info.h common/debug.h common/error.auto.h common/error.h common/ini.h common/io/filter/filter.h common/io/filter/group.h common/io/handleWrite.h common/io/read.h common/io/write.h common/lock.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/json.h common/type/keyValue.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h config/config.auto.h config/config.h config/define.auto.h config/define.h crypto/crypto.h crypto/hash.h info/info.h info/infoArchive.h info/infoBackup.h info/infoPg.h perl/exec.h postgres/interface.h storage/fileRead.h storage/fileWrite.h storage/helper.h storage/info.h storage/storage.h command/info/info.o: command/info/info.c command/archive/common.h command/info/info.h common/debug.h common/error.auto.h common/error.h common/ini.h common/io/filter/filter.h common/io/filter/group.h common/io/handleWrite.h common/io/read.h common/io/write.h common/lock.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/json.h common/type/keyValue.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h config/config.auto.h config/config.h config/define.auto.h config/define.h crypto/crypto.h crypto/hash.h info/info.h info/infoArchive.h info/infoBackup.h info/infoPg.h perl/exec.h postgres/interface.h storage/fileRead.h storage/fileWrite.h storage/helper.h storage/info.h storage/storage.h
@ -228,7 +229,10 @@ common/io/filter/group.o: common/io/filter/group.c common/assert.h common/debug.
common/io/filter/size.o: common/io/filter/size.c common/debug.h common/error.auto.h common/error.h common/io/filter/filter.h common/io/filter/filter.intern.h common/io/filter/size.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/string.h common/type/variant.h common/type/variantList.h common/io/filter/size.o: common/io/filter/size.c common/debug.h common/error.auto.h common/error.h common/io/filter/filter.h common/io/filter/filter.intern.h common/io/filter/size.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/string.h common/type/variant.h common/type/variantList.h
$(CC) $(CFLAGS) -c common/io/filter/size.c -o common/io/filter/size.o $(CC) $(CFLAGS) -c common/io/filter/size.c -o common/io/filter/size.o
common/io/handleWrite.o: common/io/handleWrite.c common/debug.h common/error.auto.h common/error.h common/io/handleWrite.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/type/buffer.h common/type/convert.h common/type/string.h common/io/handleRead.o: common/io/handleRead.c common/assert.h common/debug.h common/error.auto.h common/error.h common/io/filter/filter.h common/io/filter/group.h common/io/handleRead.h common/io/read.h common/io/read.intern.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/string.h common/type/variant.h common/type/variantList.h
$(CC) $(CFLAGS) -c common/io/handleRead.c -o common/io/handleRead.o
common/io/handleWrite.o: common/io/handleWrite.c common/assert.h common/debug.h common/error.auto.h common/error.h common/io/filter/filter.h common/io/filter/group.h common/io/handleWrite.h common/io/write.h common/io/write.intern.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/string.h common/type/variant.h common/type/variantList.h
$(CC) $(CFLAGS) -c common/io/handleWrite.c -o common/io/handleWrite.o $(CC) $(CFLAGS) -c common/io/handleWrite.c -o common/io/handleWrite.o
common/io/http/client.o: common/io/http/client.c common/assert.h common/debug.h common/error.auto.h common/error.h common/io/filter/filter.h common/io/filter/group.h common/io/http/client.h common/io/http/common.h common/io/http/header.h common/io/http/query.h common/io/io.h common/io/read.h common/io/read.intern.h common/io/tls/client.h common/io/write.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h common/wait.h common/io/http/client.o: common/io/http/client.c common/assert.h common/debug.h common/error.auto.h common/error.h common/io/filter/filter.h common/io/filter/group.h common/io/http/client.h common/io/http/common.h common/io/http/header.h common/io/http/query.h common/io/io.h common/io/read.h common/io/read.intern.h common/io/tls/client.h common/io/write.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h common/wait.h

178
src/common/io/handleRead.c Normal file
View File

@ -0,0 +1,178 @@
/***********************************************************************************************************************************
Handle IO Read
***********************************************************************************************************************************/
#include <unistd.h>
#include "common/assert.h"
#include "common/debug.h"
#include "common/io/handleRead.h"
#include "common/io/read.intern.h"
#include "common/log.h"
#include "common/memContext.h"
/***********************************************************************************************************************************
Object type
***********************************************************************************************************************************/
struct IoHandleRead
{
MemContext *memContext; // Object memory context
IoRead *io; // IoRead interface
const String *name; // Handle name for error messages
int handle; // Handle to read data from
TimeMSec timeout; // Timeout for read operation
bool eof; // Has the end of the stream been reached?
};
/***********************************************************************************************************************************
New object
***********************************************************************************************************************************/
IoHandleRead *
ioHandleReadNew(const String *name, int handle, TimeMSec timeout)
{
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(INT, handle);
FUNCTION_TEST_ASSERT(handle != -1);
FUNCTION_DEBUG_END();
IoHandleRead *this = NULL;
MEM_CONTEXT_NEW_BEGIN("IoHandleRead")
{
this = memNew(sizeof(IoHandleRead));
this->memContext = memContextCurrent();
this->io = ioReadNewP(this, .eof = (IoReadInterfaceEof)ioHandleReadEof, .read = (IoReadInterfaceRead)ioHandleRead);
this->name = strDup(name);
this->handle = handle;
this->timeout = timeout;
}
MEM_CONTEXT_NEW_END();
FUNCTION_DEBUG_RESULT(IO_HANDLE_READ, this);
}
/***********************************************************************************************************************************
Read data from the handle
***********************************************************************************************************************************/
size_t
ioHandleRead(IoHandleRead *this, Buffer *buffer, bool block)
{
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(IO_HANDLE_READ, this);
FUNCTION_DEBUG_PARAM(BUFFER, buffer);
FUNCTION_DEBUG_PARAM(BOOL, block);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_ASSERT(buffer != NULL);
FUNCTION_TEST_ASSERT(!bufFull(buffer));
FUNCTION_DEBUG_END();
ssize_t actualBytes = 0;
// If blocking keep reading until buffer is full or eof
if (!this->eof)
{
do
{
// Initialize the file descriptor set used for select
fd_set selectSet;
FD_ZERO(&selectSet);
// We know the handle is not negative because it passed error handling, so it is safe to cast to unsigned
FD_SET((unsigned int)this->handle, &selectSet);
// Initialize timeout struct used for select. Recreate this structure each time since Linux (at least) will modify it.
struct timeval timeoutSelect;
timeoutSelect.tv_sec = (time_t)(this->timeout / MSEC_PER_SEC);
timeoutSelect.tv_usec = (time_t)(this->timeout % MSEC_PER_SEC * 1000);
// Determine if there is data to be read
int result = select(this->handle + 1, &selectSet, NULL, NULL, &timeoutSelect);
THROW_ON_SYS_ERROR_FMT(result == -1, AssertError, "unable to select from %s", strPtr(this->name));
// If no data read after time allotted then error
if (!result)
THROW_FMT(FileReadError, "unable to read data from %s after %" PRIu64 "ms", strPtr(this->name), this->timeout);
// Read and handle errors
THROW_ON_SYS_ERROR_FMT(
(actualBytes = read(this->handle, bufRemainsPtr(buffer), bufRemains(buffer))) == -1, FileReadError,
"unable to read from %s", strPtr(this->name));
// Update amount of buffer used
bufUsedInc(buffer, (size_t)actualBytes);
// If zero bytes were returned then eof
if (actualBytes == 0)
this->eof = true;
}
while (bufRemains(buffer) > 0 && !this->eof && block);
}
FUNCTION_DEBUG_RESULT(SIZE, (size_t)actualBytes);
}
/***********************************************************************************************************************************
Move the object to a new context
***********************************************************************************************************************************/
IoHandleRead *
ioHandleReadMove(IoHandleRead *this, MemContext *parentNew)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(IO_HANDLE_READ, this);
FUNCTION_TEST_PARAM(MEM_CONTEXT, parentNew);
FUNCTION_TEST_ASSERT(parentNew != NULL);
FUNCTION_TEST_END();
if (this != NULL)
memContextMove(this->memContext, parentNew);
FUNCTION_TEST_RESULT(IO_HANDLE_READ, this);
}
/***********************************************************************************************************************************
Have all bytes been read from the buffer?
***********************************************************************************************************************************/
bool
ioHandleReadEof(const IoHandleRead *this)
{
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(IO_HANDLE_READ, this);
FUNCTION_DEBUG_ASSERT(this != NULL);
FUNCTION_DEBUG_END();
FUNCTION_DEBUG_RESULT(BOOL, this->eof);
}
/***********************************************************************************************************************************
Get io interface
***********************************************************************************************************************************/
IoRead *
ioHandleReadIo(const IoHandleRead *this)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(IO_HANDLE_READ, this);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(IO_READ, this->io);
}
/***********************************************************************************************************************************
Free the object
***********************************************************************************************************************************/
void
ioHandleReadFree(IoHandleRead *this)
{
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(IO_HANDLE_READ, this);
FUNCTION_DEBUG_END();
if (this != NULL)
memContextFree(this->memContext);
FUNCTION_DEBUG_RESULT_VOID();
}

View File

@ -0,0 +1,47 @@
/***********************************************************************************************************************************
Handle IO Read
Read from a handle using the IoRead interface.
***********************************************************************************************************************************/
#ifndef COMMON_IO_HANDLEREAD_H
#define COMMON_IO_HANDLEREAD_H
/***********************************************************************************************************************************
Object type
***********************************************************************************************************************************/
typedef struct IoHandleRead IoHandleRead;
#include "common/io/read.h"
#include "common/time.h"
/***********************************************************************************************************************************
Constructor
***********************************************************************************************************************************/
IoHandleRead *ioHandleReadNew(const String *name, int handle, TimeMSec timeout);
/***********************************************************************************************************************************
Functions
***********************************************************************************************************************************/
size_t ioHandleRead(IoHandleRead *this, Buffer *buffer, bool block);
IoHandleRead *ioHandleReadMove(IoHandleRead *this, MemContext *parentNew);
/***********************************************************************************************************************************
Getters
***********************************************************************************************************************************/
bool ioHandleReadEof(const IoHandleRead *this);
IoRead *ioHandleReadIo(const IoHandleRead *this);
/***********************************************************************************************************************************
Destructor
***********************************************************************************************************************************/
void ioHandleReadFree(IoHandleRead *this);
/***********************************************************************************************************************************
Macros for function logging
***********************************************************************************************************************************/
#define FUNCTION_DEBUG_IO_HANDLE_READ_TYPE \
IoHandleRead *
#define FUNCTION_DEBUG_IO_HANDLE_READ_FORMAT(value, buffer, bufferSize) \
objToLog(value, "IoHandleRead", buffer, bufferSize)
#endif

View File

@ -3,10 +3,118 @@ Handle IO Write
***********************************************************************************************************************************/ ***********************************************************************************************************************************/
#include <unistd.h> #include <unistd.h>
#include "common/assert.h"
#include "common/debug.h" #include "common/debug.h"
#include "common/error.h"
#include "common/io/handleWrite.h" #include "common/io/handleWrite.h"
#include "common/io/write.intern.h"
#include "common/log.h" #include "common/log.h"
#include "common/memContext.h"
/***********************************************************************************************************************************
Object type
***********************************************************************************************************************************/
struct IoHandleWrite
{
MemContext *memContext; // Object memory context
IoWrite *io; // IoWrite interface
const String *name; // Handle name for error messages
int handle; // Handle to write to
};
/***********************************************************************************************************************************
New object
***********************************************************************************************************************************/
IoHandleWrite *
ioHandleWriteNew(const String *name, int handle)
{
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(INT, handle);
FUNCTION_DEBUG_END();
IoHandleWrite *this = NULL;
MEM_CONTEXT_NEW_BEGIN("IoHandleWrite")
{
this = memNew(sizeof(IoHandleWrite));
this->memContext = memContextCurrent();
this->io = ioWriteNewP(this, .write = (IoWriteInterfaceWrite)ioHandleWrite);
this->name = strDup(name);
this->handle = handle;
}
MEM_CONTEXT_NEW_END();
FUNCTION_DEBUG_RESULT(IO_HANDLE_WRITE, this);
}
/***********************************************************************************************************************************
Write to the handle
***********************************************************************************************************************************/
void
ioHandleWrite(IoHandleWrite *this, Buffer *buffer)
{
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(IO_HANDLE_WRITE, this);
FUNCTION_DEBUG_PARAM(BUFFER, buffer);
FUNCTION_DEBUG_ASSERT(this != NULL);
FUNCTION_DEBUG_ASSERT(buffer != NULL);
FUNCTION_DEBUG_END();
THROW_ON_SYS_ERROR_FMT(
write(this->handle, bufPtr(buffer), bufUsed(buffer)) == -1, FileWriteError, "unable to write to %s", strPtr(this->name));
FUNCTION_DEBUG_RESULT_VOID();
}
/***********************************************************************************************************************************
Move the object to a new context
***********************************************************************************************************************************/
IoHandleWrite *
ioHandleWriteMove(IoHandleWrite *this, MemContext *parentNew)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(IO_HANDLE_WRITE, this);
FUNCTION_TEST_PARAM(MEM_CONTEXT, parentNew);
FUNCTION_TEST_ASSERT(parentNew != NULL);
FUNCTION_TEST_END();
if (this != NULL)
memContextMove(this->memContext, parentNew);
FUNCTION_TEST_RESULT(IO_HANDLE_WRITE, this);
}
/***********************************************************************************************************************************
Get io interface
***********************************************************************************************************************************/
IoWrite *
ioHandleWriteIo(const IoHandleWrite *this)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(IO_HANDLE_WRITE, this);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(IO_WRITE, this->io);
}
/***********************************************************************************************************************************
Free the object
***********************************************************************************************************************************/
void
ioHandleWriteFree(IoHandleWrite *this)
{
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(IO_HANDLE_WRITE, this);
FUNCTION_DEBUG_END();
if (this != NULL)
memContextFree(this->memContext);
FUNCTION_DEBUG_RESULT_VOID();
}
/*********************************************************************************************************************************** /***********************************************************************************************************************************
Write a string to the specified handle Write a string to the specified handle
@ -22,7 +130,7 @@ ioHandleWriteOneStr(int handle, const String *string)
FUNCTION_DEBUG_END(); FUNCTION_DEBUG_END();
if (write(handle, strPtr(string), strSize(string)) != (int)strSize(string)) if (write(handle, strPtr(string), strSize(string)) != (int)strSize(string))
THROW_SYS_ERROR_FMT(FileWriteError, "unable to write %zu byte(s) to handle", strSize(string)); THROW_SYS_ERROR(FileWriteError, "unable to write to handle");
FUNCTION_DEBUG_RESULT_VOID(); FUNCTION_DEBUG_RESULT_VOID();
} }

View File

@ -1,16 +1,50 @@
/*********************************************************************************************************************************** /***********************************************************************************************************************************
Handle IO Write Handle IO Write
Simple IO write functions operating on handles. These will be superceded by general IoRead/IoWrite functionality. Write to a handle using the IoWrite interface.
***********************************************************************************************************************************/ ***********************************************************************************************************************************/
#ifndef COMMON_IO_HANDLEWRITE_H #ifndef COMMON_IO_HANDLEWRITE_H
#define COMMON_IO_HANDLEWRITE_H #define COMMON_IO_HANDLEWRITE_H
#include "common/type/string.h" /***********************************************************************************************************************************
Object type
***********************************************************************************************************************************/
typedef struct IoHandleWrite IoHandleWrite;
#include "common/io/write.h"
/***********************************************************************************************************************************
Constructor
***********************************************************************************************************************************/
IoHandleWrite *ioHandleWriteNew(const String *name, int handle);
/*********************************************************************************************************************************** /***********************************************************************************************************************************
Functions Functions
***********************************************************************************************************************************/ ***********************************************************************************************************************************/
void ioHandleWrite(IoHandleWrite *this, Buffer *buffer);
IoHandleWrite *ioHandleWriteMove(IoHandleWrite *this, MemContext *parentNew);
/***********************************************************************************************************************************
Getters
***********************************************************************************************************************************/
IoWrite *ioHandleWriteIo(const IoHandleWrite *this);
/***********************************************************************************************************************************
Destructor
***********************************************************************************************************************************/
void ioHandleWriteFree(IoHandleWrite *this);
/***********************************************************************************************************************************
Helper functions
***********************************************************************************************************************************/
void ioHandleWriteOneStr(int handle, const String *string); void ioHandleWriteOneStr(int handle, const String *string);
/***********************************************************************************************************************************
Macros for function logging
***********************************************************************************************************************************/
#define FUNCTION_DEBUG_IO_HANDLE_WRITE_TYPE \
IoHandleWrite *
#define FUNCTION_DEBUG_IO_HANDLE_WRITE_FORMAT(value, buffer, bufferSize) \
objToLog(value, "IoHandleWrite", buffer, bufferSize)
#endif #endif

View File

@ -208,6 +208,7 @@ unit:
common/io/filter/filter: full common/io/filter/filter: full
common/io/filter/group: full common/io/filter/group: full
common/io/filter/size: full common/io/filter/size: full
common/io/handleRead: full
common/io/handleWrite: full common/io/handleWrite: full
common/io/io: full common/io/io: full
common/io/read: full common/io/read: full

View File

@ -5,6 +5,8 @@ Test IO
#include "common/assert.h" #include "common/assert.h"
#include "common/harnessFork.h"
/*********************************************************************************************************************************** /***********************************************************************************************************************************
Test functions for IoRead that are not covered by testing the IoBufferRead object Test functions for IoRead that are not covered by testing the IoBufferRead object
***********************************************************************************************************************************/ ***********************************************************************************************************************************/
@ -451,11 +453,104 @@ testRun(void)
} }
// ***************************************************************************************************************************** // *****************************************************************************************************************************
if (testBegin("ioHandleWriteOneStr()")) if (testBegin("IoHandleRead, IoHandleWrite, and ioHandleWriteOneStr()"))
{ {
ioBufferSizeSet(16);
// Create pipe for testing
int pipeTest[2];
THROW_ON_SYS_ERROR(pipe(pipeTest) == -1, KernelError, "unable to create test pipe");
HARNESS_FORK_BEGIN()
{
HARNESS_FORK_CHILD()
{
close(pipeTest[0]);
IoHandleWrite *write = NULL;
MEM_CONTEXT_TEMP_BEGIN()
{
TEST_RESULT_VOID(ioHandleWriteMove(NULL, MEM_CONTEXT_OLD()), "move null write");
TEST_ASSIGN(
write, ioHandleWriteMove(ioHandleWriteNew(strNew("write test"), pipeTest[1]), MEM_CONTEXT_OLD()),
"move write");
}
MEM_CONTEXT_TEMP_END();
ioWriteOpen(ioHandleWriteIo(write));
// Write a line to be read
TEST_RESULT_VOID(ioWriteLine(ioHandleWriteIo(write), strNew("test string 1")), "write test string");
ioWriteFlush(ioHandleWriteIo(write));
// Sleep so the other side will timeout
Buffer *buffer = bufNewStr(strNew("12345678"));
TEST_RESULT_VOID(ioWrite(ioHandleWriteIo(write), buffer), "write buffer");
sleepMSec(1250);
// Write a buffer in two parts and sleep in the middle so it will be read on the other side in two parts
TEST_RESULT_VOID(ioWrite(ioHandleWriteIo(write), buffer), "write buffer");
sleepMSec(500);
TEST_RESULT_VOID(ioWrite(ioHandleWriteIo(write), buffer), "write buffer");
ioWriteFlush(ioHandleWriteIo(write));
// Free object
TEST_RESULT_VOID(ioHandleWriteFree(NULL), "free null write");
TEST_RESULT_VOID(ioHandleWriteFree(write), "free write");
close(pipeTest[1]);
}
HARNESS_FORK_PARENT()
{
close(pipeTest[1]);
IoHandleRead *read = NULL;
MEM_CONTEXT_TEMP_BEGIN()
{
TEST_RESULT_VOID(ioHandleReadMove(NULL, MEM_CONTEXT_OLD()), "move null read");
TEST_ASSIGN(
read, ioHandleReadMove(ioHandleReadNew(strNew("read test"), pipeTest[0], 1000), MEM_CONTEXT_OLD()),
"move read");
}
MEM_CONTEXT_TEMP_END();
ioReadOpen(ioHandleReadIo(read));
// Read a string
TEST_RESULT_STR(strPtr(ioReadLine(ioHandleReadIo(read))), "test string 1", "read test string");
// Only part of the buffer is written before timeout
Buffer *buffer = bufNew(16);
TEST_ERROR(ioRead(ioHandleReadIo(read), buffer), FileReadError, "unable to read data from read test after 1000ms");
TEST_RESULT_UINT(bufSize(buffer), 16, "buffer is only partially read");
// Not read a buffer that is transmitted in two parts
buffer = bufNew(16);
TEST_RESULT_UINT(ioRead(ioHandleReadIo(read), buffer), 16, "read buffer");
TEST_RESULT_STR(strPtr(strNewBuf(buffer)), "1234567812345678", "check buffer");
// Check EOF
buffer = bufNew(16);
TEST_RESULT_UINT(ioHandleRead(read, buffer, true), 0, "read buffer at eof");
TEST_RESULT_UINT(ioHandleRead(read, buffer, true), 0, "read buffer at eof again");
// Free object
TEST_RESULT_VOID(ioHandleReadFree(NULL), "free null read");
TEST_RESULT_VOID(ioHandleReadFree(read), "free read");
close(pipeTest[0]);
}
}
HARNESS_FORK_END();
// -------------------------------------------------------------------------------------------------------------------------
TEST_ERROR( TEST_ERROR(
ioHandleWriteOneStr(999999, strNew("test")), FileWriteError, ioHandleWriteOneStr(999999, strNew("test")), FileWriteError,
"unable to write 4 byte(s) to handle: [9] Bad file descriptor"); "unable to write to handle: [9] Bad file descriptor");
// ------------------------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------------------------
String *fileName = strNewFmt("%s/test.txt", testPath()); String *fileName = strNewFmt("%s/test.txt", testPath());