You've already forked pgbackrest
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:
@ -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>
|
||||||
|
@ -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
178
src/common/io/handleRead.c
Normal 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();
|
||||||
|
}
|
47
src/common/io/handleRead.h
Normal file
47
src/common/io/handleRead.h
Normal 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
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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());
|
||||||
|
Reference in New Issue
Block a user