Skip to content
This repository has been archived by the owner on Jan 18, 2022. It is now read-only.

Native Event Tracing IO Wrappers #1444

Merged
merged 21 commits into from
Aug 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
### Internal

- Added C# bindings for C Event Tracing API. [#1440](https://github.com/spatialos/gdk-for-unity/pull/1440)
- Added native classes for IO operations in Event Tracing API. [#1444](https://github.com/spatialos/gdk-for-unity/pull/1444)

## `0.3.9` - 2020-07-24

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ public struct EventTracerParameters
*/
[DllImport(Constants.WorkerLibrary, CallingConvention = CallingConvention.Cdecl,
EntryPoint = "Trace_Item_Create")]
public static extern Item* ItemCreate(CIO.Storage storage, Item* item);
public static extern Item* ItemCreate(CIO.StorageHandle storage, Item* item);

/**
* Returns a pointer to a thread-local trace item.
Expand Down Expand Up @@ -320,7 +320,7 @@ public struct EventTracerParameters
*/
[DllImport(Constants.WorkerLibrary, CallingConvention = CallingConvention.Cdecl,
EntryPoint = "Trace_SerializeItemToStream")]
public static extern Int8 SerializeItemToStream(CIO.Stream stream, Item* item, Uint32 size);
public static extern Int8 SerializeItemToStream(CIO.StreamHandle stream, Item* item, Uint32 size);

/**
* Get the serialized size, in bytes, of the next serialized trace item to be read from the stream.
Expand All @@ -332,7 +332,7 @@ public struct EventTracerParameters
*/
[DllImport(Constants.WorkerLibrary, CallingConvention = CallingConvention.Cdecl,
EntryPoint = "Trace_GetNextSerializedItemSize")]
public static extern Uint32 GetNextSerializedItemSize(CIO.Stream stream);
public static extern Uint32 GetNextSerializedItemSize(CIO.StreamHandle stream);

/**
* Deserialize the next trace item from the stream.
Expand All @@ -356,7 +356,7 @@ public struct EventTracerParameters
*/
[DllImport(Constants.WorkerLibrary, CallingConvention = CallingConvention.Cdecl,
EntryPoint = "Trace_DeserializeItemFromStream")]
public static extern Int8 DeserializeItemFromStream(CIO.Stream stream, Item* item, Uint32 size);
public static extern Int8 DeserializeItemFromStream(CIO.StreamHandle stream, Item* item, Uint32 size);

/**
* Returns the last error which occurred during a trace API method call. Returns nullptr if no
Expand Down
28 changes: 14 additions & 14 deletions workers/unity/Packages/io.improbable.worker.sdk/CIO.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace Improbable.Worker.CInterop.Internal
{
internal unsafe class CIO
{
public class Storage : CptrHandle
public class StorageHandle : CptrHandle
{
protected override bool ReleaseHandle()
{
Expand All @@ -19,7 +19,7 @@ protected override bool ReleaseHandle()
}
}

public class Stream : CptrHandle
public class StreamHandle : CptrHandle
{
protected override bool ReleaseHandle()
{
Expand All @@ -45,7 +45,7 @@ public enum OpenMode
*/
[DllImport(Constants.WorkerLibrary, CallingConvention = CallingConvention.Cdecl,
EntryPoint = "Io_Storage_Create")]
public static extern Storage StorageCreate();
public static extern StorageHandle StorageCreate();

/* Destroys the trace storage. */
[DllImport(Constants.WorkerLibrary, CallingConvention = CallingConvention.Cdecl,
Expand All @@ -61,7 +61,7 @@ public enum OpenMode
*/
[DllImport(Constants.WorkerLibrary, CallingConvention = CallingConvention.Cdecl,
EntryPoint = "Io_Storage_Clear")]
public static extern void StorageClear(IntPtr storage);
public static extern void StorageClear(StorageHandle storage);

/**
* Creates an I/O stream implemented as a ring buffer.
Expand All @@ -77,7 +77,7 @@ public enum OpenMode
*/
[DllImport(Constants.WorkerLibrary, CallingConvention = CallingConvention.Cdecl,
EntryPoint = "Io_CreateRingBufferStream")]
public static extern Stream CreateRingBufferStream(Uint32 capacityBytes);
public static extern StreamHandle CreateRingBufferStream(Uint32 capacityBytes);

/**
* Creates an I/O stream implemented as a read/write file.
Expand All @@ -94,7 +94,7 @@ public enum OpenMode
*/
[DllImport(Constants.WorkerLibrary, CallingConvention = CallingConvention.Cdecl,
EntryPoint = "Io_CreateFileStream")]
public static extern Stream CreateFileStream(Char* filename, OpenMode openMode);
public static extern StreamHandle CreateFileStream(Char* filename, OpenMode openMode);

/* Destroys the I/O stream. */
[DllImport(Constants.WorkerLibrary, CallingConvention = CallingConvention.Cdecl,
Expand All @@ -111,7 +111,7 @@ public enum OpenMode
*/
[DllImport(Constants.WorkerLibrary, CallingConvention = CallingConvention.Cdecl,
EntryPoint = "Io_Stream_Write")]
public static extern Int64 StreamWrite(Stream stream, Uint8* bytes, Uint32 length);
public static extern Int64 StreamWrite(StreamHandle stream, Uint8* bytes, Uint32 length);

/**
* Gets the remaining write capacity in bytes.
Expand All @@ -121,7 +121,7 @@ public enum OpenMode
*/
[DllImport(Constants.WorkerLibrary, CallingConvention = CallingConvention.Cdecl,
EntryPoint = "Io_Stream_GetRemainingWriteCapacityBytes")]
public static extern Uint32 StreamGetRemainingWriteCapacityBytes(Stream stream);
public static extern Uint32 StreamGetRemainingWriteCapacityBytes(StreamHandle stream);

/**
* Reads as much of the stream's data as possible into the given buffer.
Expand All @@ -133,7 +133,7 @@ public enum OpenMode
*/
[DllImport(Constants.WorkerLibrary, CallingConvention = CallingConvention.Cdecl,
EntryPoint = "Io_Stream_Read")]
public static extern Uint64 StreamRead(Stream stream, Uint8* bytes, Uint32 length);
public static extern Int64 StreamRead(StreamHandle stream, Uint8* bytes, Uint32 length);

/**
* Reads as much of the stream's data as possible into the given buffer without advancing the read
Expand All @@ -142,11 +142,11 @@ public enum OpenMode
* Returns the actual number of bytes read. This may be less than the given length iff the stream
* has less data than the requested amount.
*
* Returns -1 on error. Call StreamGetLastError() to get the associated error message.
* Returns -1 on error. Call StreamGetLastError to get the associated error message.
*/
[DllImport(Constants.WorkerLibrary, CallingConvention = CallingConvention.Cdecl,
EntryPoint = "Io_Stream_Peek")]
public static extern Int64 StreamPeek(Stream stream, Uint8* bytes, Uint32 length);
public static extern Int64 StreamPeek(StreamHandle stream, Uint8* bytes, Uint32 length);

/**
* Extracts the given number of bytes from the stream and discards them.
Expand All @@ -155,18 +155,18 @@ public enum OpenMode
* has advanced. This may be less than the given length iff the stream has less data than the
* requested amount.
*
* Returns -1 on error. Call StreamGetLastError() to get the associated error message.
* Returns -1 on error. Call StreamGetLastError to get the associated error message.
*/
[DllImport(Constants.WorkerLibrary, CallingConvention = CallingConvention.Cdecl,
EntryPoint = "Io_Stream_Ignore")]
public static extern Int64 StreamIgnore(Stream stream, Uint32 length);
public static extern Int64 StreamIgnore(StreamHandle stream, Uint32 length);

/**
* Returns the last error which occurred during an API call on this stream. Returns nullptr if no
* such error has occurred.
*/
[DllImport(Constants.WorkerLibrary, CallingConvention = CallingConvention.Cdecl,
EntryPoint = "Io_Stream_GetLastError")]
public static extern Char* StreamGetLastError(Stream stream);
public static extern Char* StreamGetLastError(StreamHandle stream);
}
}
26 changes: 26 additions & 0 deletions workers/unity/Packages/io.improbable.worker.sdk/IOStorage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System;
using Improbable.Worker.CInterop.Internal;

namespace Improbable.Worker.CInterop
{
public sealed class IOStorage : IDisposable
{
private readonly CIO.StorageHandle storage;

public IOStorage()
{
storage = CIO.StorageCreate();
}

/// <inheritdoc cref="IDisposable"/>
public void Dispose()
{
storage.Dispose();
}

public void Clear()
{
CIO.StorageClear(storage);
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

156 changes: 156 additions & 0 deletions workers/unity/Packages/io.improbable.worker.sdk/IOStream.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
using System;
using System.IO;
using Improbable.Worker.CInterop.Internal;

namespace Improbable.Worker.CInterop
{
public enum OpenMode
{
/* Opens the stream in the default mode. */
OpenModeDefault = 0x00,
}

public sealed unsafe class IOStream : IDisposable
{
private readonly CIO.StreamHandle stream;

private IOStream(CIO.StreamHandle stream)
{
this.stream = stream;
}

/// <inheritdoc cref="IDisposable"/>
public void Dispose()
{
stream.Dispose();
}

public static IOStream CreateRingBufferStream(uint capacity)
{
return new IOStream(CIO.CreateRingBufferStream(capacity));
}

public static IOStream CreateFileStream(string fileName, OpenMode openMode)
{
fixed (byte* fileNameBytes = ApiInterop.ToUtf8Cstr(fileName))
{
return new IOStream(CIO.CreateFileStream(fileNameBytes, (CIO.OpenMode) openMode));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if this kind of cast is actually valid. the C# Interop has some fancy conversion class for this reason.
Might want to double check

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be a compiler error if it was an invalid cast I think (the as casts fail at runtime)

}
}

public long Write(byte[] data)
{
ThrowIfStreamClosed();

var remainingCapacity = CIO.StreamGetRemainingWriteCapacityBytes(stream);
if (remainingCapacity < data.Length)
{
throw new NotSupportedException("Not enough stream capacity to write data.");
}

var bytesWritten = 0L;
fixed (byte* dataToWrite = data)
seanjparker marked this conversation as resolved.
Show resolved Hide resolved
{
bytesWritten = CIO.StreamWrite(stream, dataToWrite, 1);
}

if (bytesWritten != -1)
{
return bytesWritten;
}

var rawError = CIO.StreamGetLastError(stream);
throw new IOException(ApiInterop.FromUtf8Cstr(rawError));
}

public long Read(uint bytesToRead, out byte[] streamData)
{
ThrowIfStreamClosed();

streamData = new byte[bytesToRead];

var bytesRead = 0L;
fixed (byte* streamDataPointer = streamData)
{
bytesRead = CIO.StreamRead(stream, streamDataPointer, bytesToRead);
}

if (bytesRead != -1)
{
return bytesRead;
}

var rawError = CIO.StreamGetLastError(stream);
throw new IOException(ApiInterop.FromUtf8Cstr(rawError));
}

public long Read(byte[] streamData)
{
ThrowIfStreamClosed();

var bytesToRead = (uint) streamData.Length;
var bytesRead = 0L;
fixed (byte* streamDataPointer = streamData)
{
bytesRead = CIO.StreamRead(stream, streamDataPointer, bytesToRead);
}

if (bytesRead != -1)
{
return bytesRead;
}

var rawError = CIO.StreamGetLastError(stream);
throw new IOException(ApiInterop.FromUtf8Cstr(rawError));
}

public long Peek(uint bytesToPeek, out byte[] streamData)
{
ThrowIfStreamClosed();

streamData = new byte[bytesToPeek];

var bytesPeeked = 0L;
fixed (byte* streamDataPointer = streamData)
{
bytesPeeked = CIO.StreamPeek(stream, streamDataPointer, bytesToPeek);
}

if (bytesPeeked != -1)
{
return bytesPeeked;
}

var rawError = CIO.StreamGetLastError(stream);
throw new IOException(ApiInterop.FromUtf8Cstr(rawError));
}

public long Ignore(uint bytesToIgnore)
{
ThrowIfStreamClosed();

var bytesIgnored = CIO.StreamIgnore(stream, bytesToIgnore);

if (bytesIgnored != -1)
{
return bytesIgnored;
}

var rawError = CIO.StreamGetLastError(stream);
throw new IOException(ApiInterop.FromUtf8Cstr(rawError));
}

public uint GetRemainingCapacity()
{
return CIO.StreamGetRemainingWriteCapacityBytes(stream);
}

private void ThrowIfStreamClosed()
{
if (stream.IsClosed)
{
throw new ObjectDisposedException("Cannot access a disposed object.");
}
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.