Skip to content
Open
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
22 changes: 11 additions & 11 deletions Unhinged.Playground/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,11 @@ private static void RequestHandler(Connection connection)
private static readonly JsonContext SerializerContext = JsonContext.Default;
private static void CommitJsonResponse(Connection connection)
{
connection.WriteBuffer.Write("HTTP/1.1 200 OK\r\n"u8 +
"Server: W\r\n"u8 +
"Content-Type: application/json; charset=UTF-8\r\n"u8 +
"Content-Length: 27\r\n"u8);
connection.WriteBuffer.Write(DateHelper.HeaderBytes);
connection.WriteBuffer.WriteUnmanaged("HTTP/1.1 200 OK\r\n"u8 +
"Server: W\r\n"u8 +
"Content-Type: application/json; charset=UTF-8\r\n"u8 +
"Content-Length: 27\r\n"u8);
connection.WriteBuffer.WriteUnmanaged(DateHelper.HeaderBytes);

t_utf8JsonWriter ??= new Utf8JsonWriter(connection.WriteBuffer, new JsonWriterOptions { SkipValidation = true });
t_utf8JsonWriter.Reset(connection.WriteBuffer);
Expand All @@ -58,13 +58,13 @@ private static void CommitJsonResponse(Connection connection)

private static void CommitPlainTextResponse(Connection connection)
{
connection.WriteBuffer.Write("HTTP/1.1 200 OK\r\n"u8 +
"Server: W\r\n"u8 +
"Content-Type: text/plain\r\n"u8 +
//"Content-Length: 13\r\n\r\nHello, World!"u8);
"Content-Length: 13\r\n"u8);
connection.WriteBuffer.WriteUnmanaged("HTTP/1.1 200 OK\r\n"u8 +
"Server: W\r\n"u8 +
"Content-Type: text/plain\r\n"u8 +
//"Content-Length: 13\r\n\r\nHello, World!"u8);
"Content-Length: 13\r\n"u8);
connection.WriteBuffer.WriteUnmanaged(DateHelper.HeaderBytes);
connection.WriteBuffer.Write("Hello, World!"u8);
connection.WriteBuffer.WriteUnmanaged("Hello, World!"u8);
}
}

28 changes: 28 additions & 0 deletions Unhinged/ABI/ProcessorArchDependant.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,34 @@ internal static void ReadEpollEvent(void* src, out uint events, out int fd)
fd = (int)*(uint*)((byte*)src + 8);
}
}

// Variations, TODO: Test performance required

[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
internal static void WriteEpollEvent2(void* dest, uint events, int fd)
{
// Write events (always aligned 4B store)
*(uint*)dest = events;

// Compute data offset (packed: +4, natural: +8)
var data = (byte*)dest + (Packed ? 4 : 8);

// Store only low 32 bits of fd and zero the high 32 bits.
// Using two 4B stores avoids an unaligned 8B write in the packed layout.
*(uint*)data = (uint)fd; // low 32
*(uint*)(data + 4) = 0; // high 32
}

[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
internal static void ReadEpollEvent2(void* src, out uint events, out int fd)
{
events = *(uint*)src;

var data = (byte*)src + (Packed ? 4 : 8);

// We only ever wrote the low 32 bits; read exactly those.
fd = (int)*(uint*)data;
}

// =============================================================================================
// Networking helpers
Expand Down
2 changes: 1 addition & 1 deletion Unhinged/Engine/UnhingedEngine.Acceptor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ private static void AcceptorLoop(int listenFd, Worker[] workers)
workers[w].Inbox.Enqueue(cfd); // hand off fd to worker queue
Interlocked.Increment(ref workers[w].Current); // bump worker load metric

//Console.WriteLine($"Incremented {workers[w].Ep} with cfg {cfd} to {workers[w].Current}");
Console.WriteLine($"Incremented {workers[w].Ep} with cfg {cfd} to {workers[w].Current}");

// Wake the worker via eventfd. We write 8 bytes (uint64).
ulong inc = 1;
Expand Down
29 changes: 21 additions & 8 deletions Unhinged/Engine/UnhingedEngine.Worker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
// ReSharper disable always StackAllocInsideLoop
// ReSharper disable always ClassCannotBeInstantiated

using System.Text;

#pragma warning disable CA2014

namespace Unhinged;
Expand Down Expand Up @@ -129,13 +131,12 @@ private static void WorkerLoop(Worker W)
long got;
//fixed (byte* p = &c.Buf[c.Tail])
// got = recv(fd, (IntPtr)p, (ulong)avail, 0);
got = recv(fd, c.ReceiveBuffer, (ulong)avail, 0);
got = recv(fd, c.ReceiveBuffer + c.Tail, (ulong)avail, 0);

if (got > 0)
{
c.Tail += (int)got;
continue;

}
if (got == 0) { CloseConn(fd, connections, W); break; } // peer closed

Expand Down Expand Up @@ -226,6 +227,7 @@ private static bool TryParseRequests(Connection connection)
//int idx = FindCrlfCrlf(connection.Buf, connection.Head, connection.Tail);
//int idx = FindCrlfCrlf(connection.ReceiveBuffer, connection.Head, connection.Tail);
var headerSpan = FindCrlfCrlf(connection.ReceiveBuffer, connection.Head, connection.Tail, out int idx);

if (idx < 0)
break;

Expand All @@ -240,12 +242,16 @@ private static bool TryParseRequests(Connection connection)

// Mark that there is data to flush (a request was fully processed)
hasDataToFlush = true;

if (connection.Head == connection.Tail)
break;
}

// If there is unprocessed data in the receiving buffer (incomplete request) which is not at buffer start
// Move the incomplete request to the buffer start and reset head and tail to 0
if (connection.Head > 0 && connection.Head < connection.Tail)
{
Console.WriteLine("= Unprocessed data =");
Buffer.MemoryCopy(
connection.ReceiveBuffer + connection.Head,
connection.ReceiveBuffer,
Expand Down Expand Up @@ -347,13 +353,20 @@ private static void CloseConn(int fd, Dictionary<int, Connection> map, Worker W)
{
// Remove from map, close fd, and decrement the worker's load counter.
// TODO: Defensive check if entry exists in the map before trying to remove it?
ConnectionPool.Return(map[fd]);
map.Remove(fd);
try
{
ConnectionPool.Return(map[fd]);
map.Remove(fd);

//Console.WriteLine($"Closing {fd}");

CloseQuiet(fd);
Interlocked.Decrement(ref W.Current);
//Console.WriteLine($"Closing {fd}");

CloseQuiet(fd);
Interlocked.Decrement(ref W.Current);
}
catch
{
// TODO: Complete this.
}
}

/// <summary>
Expand Down
6 changes: 6 additions & 0 deletions Unhinged/HttpProtocol/HeaderParsing.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
// (var is avoided intentionally in this project so that concrete types are visible at call sites.)
// ReSharper disable always StackAllocInsideLoop
// ReSharper disable always ClassCannotBeInstantiated

using System.Text;

#pragma warning disable CA2014

namespace Unhinged;
Expand Down Expand Up @@ -61,6 +64,9 @@ internal static ReadOnlySpan<byte> FindCrlfCrlf(byte* buf, int head, int tail, o
// The caller must guarantee that (tail - head) bytes are valid and readable.
var span = new ReadOnlySpan<byte>(buf + head, tail - head);

//Console.WriteLine($"Spitting buffer: {head} {tail} {tail-head}");
//Console.WriteLine(Encoding.UTF8.GetString(span));

idx = span.IndexOf(CrlfCrlf);
if (idx >= 0)
idx += head;
Expand Down
6 changes: 3 additions & 3 deletions Unhinged/Unhinged.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
<Authors>Diogo Martins</Authors>
<RepositoryUrl>https://github.com/MDA2AV/Unhinged</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<AssemblyVersion>9.0.1</AssemblyVersion>
<FileVersion>9.0.1</FileVersion>
<Version>9.0.1</Version>
<AssemblyVersion>9.0.2</AssemblyVersion>
<FileVersion>9.0.2</FileVersion>
<Version>9.0.2</Version>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageTags>Unhinged</PackageTags>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
Expand Down