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

Commit

Permalink
Native Event Tracing IO Wrappers (#1444)
Browse files Browse the repository at this point in the history
* Add IOStream native wrapper

* Add IOStorage native wrapper

* Add changelog entry

* Add sealed to IOStorage class

* Remove GC SuppressFinalize call
  • Loading branch information
Sean Parker authored Aug 6, 2020
1 parent 31251a5 commit ad77599
Show file tree
Hide file tree
Showing 7 changed files with 207 additions and 18 deletions.
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));
}
}

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)
{
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.

0 comments on commit ad77599

Please sign in to comment.