diff --git a/README.md b/README.md index 0f4cd37..7afbdce 100644 --- a/README.md +++ b/README.md @@ -235,6 +235,28 @@ To bring forth the driver: zig build phi --release=[fast|safe|small] ``` +To build Phi without a Xeon Phi card, enable host emulation: + +``` +zig build phi -Dphi-host-emulation=true --release=[fast|safe|small] +``` + +In this mode the daemon is compiled natively through Zig's `std.Build` C compilation support and installed as `zig-out/bin/phi_device-host`. The driver exposes one synthetic Phi physical device and communicates with the daemon over an IPv4 TCP socket bound only to `127.0.0.1`. The client socket is implemented directly with Zig's `std.Io.net` API; it does not reuse daemon C transport functions or load `libmicmgmt` or `libscif`. + +The driver first connects to an already-running daemon. If none is listening, it launches its embedded daemon locally and retries the connection. The temporary embedded executable removes its own filesystem entry after launch. The daemon may also be started manually: + +``` +./zig-out/bin/phi_device-host +``` + +The loopback port defaults to `43616` and may be selected at build time for both the driver and daemon: + +``` +zig build phi -Dphi-host-emulation=true -Dphi-emulation-port=43617 +``` + +Builds without `-Dphi-host-emulation=true` retain the real Xeon Phi path: the daemon is cross-compiled with the configured `k1om-mpss-linux-gcc`, deployed over SSH/SCP, and communicates through SCIF. + And for those who seek another manner of building: ``` diff --git a/build.zig b/build.zig index 71df7d7..35e867c 100644 --- a/build.zig +++ b/build.zig @@ -11,6 +11,7 @@ const ImplementationDesc = struct { vulkan_version: std.SemanticVersion, custom: ?*const fn ( *std.Build, + *Step.Options, *Step.Compile, *std.Build.Module, *std.Build.Module, @@ -20,37 +21,32 @@ const ImplementationDesc = struct { std.builtin.OptimizeMode, bool, ) anyerror!void = null, - options: ?*const fn (*std.Build, *Step.Options) anyerror!void = null, }; const implementations = [_]ImplementationDesc{ - .{ - .name = "ape", - .icd_name = "ape", - .root_source_file = "src/ape/lib.zig", - .vulkan_version = .{ .major = 1, .minor = 0, .patch = 0 }, - .custom = customApe, - }, .{ .name = "soft", .root_source_file = "src/software/lib.zig", .vulkan_version = .{ .major = 1, .minor = 0, .patch = 0 }, .custom = customSoft, - .options = optionsSoft, }, .{ .name = "flint", .root_source_file = "src/intel/lib.zig", .vulkan_version = .{ .major = 1, .minor = 0, .patch = 0 }, .custom = customFlint, - .options = optionsFlint, }, .{ .name = "phi", .root_source_file = "src/phi/lib.zig", .vulkan_version = .{ .major = 1, .minor = 0, .patch = 0 }, .custom = customPhi, - .options = optionsPhi, + }, + .{ + .name = "ape", + .icd_name = "ape", + .root_source_file = "src/ape/lib.zig", + .vulkan_version = .{ .major = 1, .minor = 0, .patch = 0 }, }, }; @@ -149,7 +145,8 @@ pub fn build(b: *std.Build) !void { const use_llvm = b.option(bool, "use-llvm", "LLVM build") orelse (b.release_mode != .off); - for (implementations) |impl| { + var implementation_modules: [implementations.len]*std.Build.Module = undefined; + for (implementations, 0..) |impl, impl_index| { const lib_mod = b.createModule(.{ .root_source_file = b.path(impl.root_source_file), .target = target, @@ -161,6 +158,7 @@ pub fn build(b: *std.Build) !void { }, }); + implementation_modules[impl_index] = lib_mod; lib_mod.addSystemIncludePath(vulkan_headers.path("include")); const lib = b.addLibrary(.{ @@ -172,12 +170,11 @@ pub fn build(b: *std.Build) !void { options.addOption(std.SemanticVersion, b.fmt("{s}_vulkan_version", .{impl.name}), impl.vulkan_version); - if (impl.custom) |func| { - func(b, lib, lib_mod, base_mod, vulkan, base_c_mod, target, optimize, use_llvm) catch continue; - } - - if (impl.options) |func| { - func(b, options) catch continue; + if (std.mem.eql(u8, impl.name, "ape")) { + for (implementations[0..impl_index], implementation_modules[0..impl_index]) |child_impl, child_mod| + lib_mod.addImport(child_impl.name, child_mod); + } else if (impl.custom) |func| { + func(b, options, lib, lib_mod, base_mod, vulkan, base_c_mod, target, optimize, use_llvm) catch continue; } const icd_file = b.addWriteFile( @@ -426,45 +423,11 @@ fn addMultithreadedCTS(b: *std.Build, target: std.Build.ResolvedTarget, impl: *c return &run.step; } -// Ape specialized functions - -fn customApe( - b: *std.Build, - lib: *Step.Compile, - lib_mod: *std.Build.Module, - base_mod: *std.Build.Module, - vulkan: *std.Build.Module, - base_c_mod: *std.Build.Module, - target: std.Build.ResolvedTarget, - optimize: std.builtin.OptimizeMode, - use_llvm: bool, -) !void { - for (implementations) |impl| { - if (std.mem.eql(u8, impl.name, "ape")) - continue; - - const mod = b.createModule(.{ - .root_source_file = b.path(impl.root_source_file), - .target = target, - .optimize = optimize, - .imports = &.{ - .{ .name = "base", .module = base_mod }, - .{ .name = "vulkan", .module = vulkan }, - }, - }); - - if (impl.custom) |func| { - func(b, lib, mod, base_mod, vulkan, base_c_mod, target, optimize, use_llvm) catch continue; - } - - lib_mod.addImport(impl.name, mod); - } -} - // Soft specialized functions fn customSoft( b: *std.Build, + options: *Step.Options, _: *Step.Compile, lib_mod: *std.Build.Module, _: *std.Build.Module, @@ -482,9 +445,7 @@ fn customSoft( lib_mod.addImport("soft_c", base_c_mod); lib_mod.addImport("spv", spv.module("spv")); -} -fn optionsSoft(b: *std.Build, options: *Step.Options) !void { const single_threaded_option = b.option(bool, "soft-single-threaded", "Single threaded runtime mode") orelse false; const shaders_simd_option = b.option(bool, "soft-shader-simd", "Shaders SIMD acceleration") orelse true; const compute_dump_early_results_table_option = b.option(u32, "soft-compute-dump-early-results-table", "Dump compute shaders results table before invocation"); @@ -502,6 +463,7 @@ fn optionsSoft(b: *std.Build, options: *Step.Options) !void { fn customFlint( b: *std.Build, + _: *Step.Options, _: *Step.Compile, lib_mod: *std.Build.Module, _: *std.Build.Module, @@ -519,15 +481,11 @@ fn customFlint( })); } -fn optionsFlint(b: *std.Build, options: *Step.Options) !void { - _ = b; - _ = options; -} - // Phi specialized functions fn customPhi( b: *std.Build, + options: *Step.Options, lib: *Step.Compile, lib_mod: *std.Build.Module, _: *std.Build.Module, @@ -537,15 +495,52 @@ fn customPhi( optimize: std.builtin.OptimizeMode, use_llvm: bool, ) !void { + const daemon_remote_path = b.option( + []const u8, + "phi-daemon-remote-path", + "Path where the Xeon Phi daemon is copied on the card", + ) orelse "/tmp/phi_device.mic"; + + const daemon_host_prefix = b.option( + []const u8, + "phi-daemon-host-prefix", + "Host prefix used to reach cards over ssh/scp; card N uses N", + ) orelse "mic"; + + options.addOption([]const u8, "phi_daemon_remote_path", daemon_remote_path); + options.addOption([]const u8, "phi_daemon_host_prefix", daemon_host_prefix); + + const host_emulation = b.option( + bool, + "phi-host-emulation", + "Run the Phi device daemon on the host over a loopback TCP socket", + ) orelse false; + const emulation_port = b.option( + u16, + "phi-emulation-port", + "Loopback TCP port used by Phi host emulation", + ) orelse 43616; + + options.addOption(bool, "phi_host_emulation", host_emulation); + options.addOption(u16, "phi_emulation_port", emulation_port); + lib_mod.addImport("phi_c", base_c_mod); - const miclib = b.lazyDependency("miclib", .{ - .target = target, - .optimize = optimize, - .@"use-llvm" = use_llvm, - }) orelse return error.UnresolvedDependency; + if (host_emulation) { + lib_mod.addImport("miclib", b.createModule(.{ + .root_source_file = b.path("src/phi/mic_stub.zig"), + .target = target, + .optimize = optimize, + })); + } else { + const miclib = b.lazyDependency("miclib", .{ + .target = target, + .optimize = optimize, + .@"use-llvm" = use_llvm, + }) orelse return error.UnresolvedDependency; - lib_mod.addImport("miclib", miclib.module("miclib")); + lib_mod.addImport("miclib", miclib.module("miclib")); + } const phi_protocol_c = b.addTranslateC(.{ .root_source_file = b.path("src/phi/shared/Protocol.h"), @@ -556,20 +551,10 @@ fn customPhi( lib_mod.addImport("phi_protocol_c", phi_protocol_c.createModule()); - // To avoid duplicated options due to Ape's custom function - if (!std.mem.eql(u8, lib.name, "vulkan_phi")) { - const daemon = try addPhiCardDaemon(b, optimize, "k1om-mpss-linux-gcc", null); - const embedded_daemon = addEmbeddedPhiDaemon(b, daemon); - lib_mod.addAnonymousImport("phi_daemon", .{ - .root_source_file = embedded_daemon, - }); - return; - } - const build_card = b.option( bool, "phi-build-daemon", - "Build Xeon Phi card daemon", + "Build the Phi device daemon", ) orelse true; if (!build_card) @@ -587,8 +572,11 @@ fn customPhi( "MPSS sysroot path", ); - const daemon = try addPhiCardDaemon(b, optimize, cc, sysroot); - const install_daemon = b.addInstallFile(daemon, "lib/phi_device.mic"); + const daemon = try addPhiDaemon(b, optimize, host_emulation, emulation_port, cc, sysroot); + const install_daemon = b.addInstallFile( + daemon, + if (host_emulation) "bin/phi_device-host" else "lib/phi_device.mic", + ); lib.step.dependOn(&install_daemon.step); const embedded_daemon = addEmbeddedPhiDaemon(b, daemon); @@ -597,24 +585,17 @@ fn customPhi( }); } -fn optionsPhi(b: *std.Build, options: *Step.Options) !void { - const daemon_remote_path = b.option( - []const u8, - "phi-daemon-remote-path", - "Path where the Xeon Phi daemon is copied on the card", - ) orelse "/tmp/phi_device.mic"; +fn addPhiDaemon( + b: *std.Build, + optimize: std.builtin.OptimizeMode, + host_emulation: bool, + emulation_port: u16, + cc: []const u8, + sysroot: ?[]const u8, +) !std.Build.LazyPath { + if (host_emulation) + return addPhiHostDaemon(b, optimize, emulation_port); - const daemon_host_prefix = b.option( - []const u8, - "phi-daemon-host-prefix", - "Host prefix used to reach cards over ssh/scp; card N uses N", - ) orelse "mic"; - - options.addOption([]const u8, "phi_daemon_remote_path", daemon_remote_path); - options.addOption([]const u8, "phi_daemon_host_prefix", daemon_host_prefix); -} - -fn addPhiCardDaemon(b: *std.Build, optimize: std.builtin.OptimizeMode, cc: []const u8, sysroot: ?[]const u8) !std.Build.LazyPath { const cmd = b.addSystemCommand(&.{cc}); cmd.addArgs(&.{ @@ -649,6 +630,7 @@ fn addPhiCardDaemon(b: *std.Build, optimize: std.builtin.OptimizeMode, cc: []con "src/phi/mic/Daemon.c", "src/phi/mic/Logger.c", "src/phi/mic/Memory.c", + "src/phi/mic/Transport.c", // Add new files here }; @@ -656,14 +638,46 @@ fn addPhiCardDaemon(b: *std.Build, optimize: std.builtin.OptimizeMode, cc: []con cmd.addFileArg(b.path(source)); } - cmd.addArgs(&.{ - "-lscif", - "-o", - }); - + cmd.addArgs(&.{ "-lscif", "-o" }); return cmd.addOutputFileArg("phi_device.mic"); } +fn addPhiHostDaemon(b: *std.Build, optimize: std.builtin.OptimizeMode, emulation_port: u16) std.Build.LazyPath { + const daemon_mod = b.createModule(.{ + .target = b.graph.host, + .optimize = optimize, + .link_libc = true, + }); + daemon_mod.addIncludePath(b.path("src/phi/mic")); + daemon_mod.addIncludePath(b.path("src/phi/shared")); + daemon_mod.addCMacro("PHI_HOST_EMULATION", "1"); + daemon_mod.addCMacro("PHI_TRANSPORT_PORT", b.fmt("{d}", .{emulation_port})); + daemon_mod.addCSourceFiles(.{ + .files = &.{ + "src/phi/mic/main.c", + "src/phi/mic/Buffer.c", + "src/phi/mic/CommandBuffer.c", + "src/phi/mic/Daemon.c", + "src/phi/mic/Logger.c", + "src/phi/mic/Memory.c", + "src/phi/mic/Transport.c", + }, + .flags = &.{ + "-std=c11", + "-Wall", + "-Wextra", + "-Wno-unused-parameter", + }, + }); + daemon_mod.linkSystemLibrary("pthread", .{}); + + const daemon = b.addExecutable(.{ + .name = "phi_device-host", + .root_module = daemon_mod, + }); + return daemon.getEmittedBin(); +} + fn addEmbeddedPhiDaemon(b: *std.Build, daemon: std.Build.LazyPath) std.Build.LazyPath { const wf = b.addWriteFiles(); _ = wf.addCopyFile(daemon, "phi_device.mic"); diff --git a/src/phi/PhiDevice.zig b/src/phi/PhiDevice.zig index c76de7d..7c02cf1 100644 --- a/src/phi/PhiDevice.zig +++ b/src/phi/PhiDevice.zig @@ -81,8 +81,11 @@ pub fn create(instance: *base.Instance, physical_device: *base.PhysicalDevice, a const phi_physical_device: *PhiPhysicalDevice = @alignCast(@fieldParentPtr("interface", physical_device)); const transport = PhiTransport.init(instance, phi_physical_device.scif_node_id) catch blk: { - // If the first connection failed, upload and launch the daemon on the card. - try uploadAndLaunchDaemon(instance, allocator, phi_physical_device.mic_device_num); + // If the first connection failed, launch the daemon on the selected device. + if (comptime config.phi_host_emulation) + try launchHostDaemon(instance, allocator) + else + try uploadAndLaunchDaemon(instance, allocator, phi_physical_device.mic_device_num); const max_connect_attempts = 3; for (0..max_connect_attempts) |attempt| { @@ -242,6 +245,37 @@ pub fn getDeviceGroupSurfacePresentModesKHR(_: *Interface, _: *base.SurfaceKHR) return .{ .local_bit_khr = true }; } +fn launchHostDaemon(instance: *base.Instance, allocator: std.mem.Allocator) VkError!void { + const io = instance.io(); + const process_id = std.os.linux.getpid(); + const thread_id = std.Thread.getCurrentId(); + + const local_path = std.fmt.allocPrint(allocator, "/tmp/ape_phi_device_{d}_{d}.host", .{ process_id, thread_id }) catch return VkError.OutOfHostMemory; + defer allocator.free(local_path); + errdefer std.Io.Dir.deleteFileAbsolute(io, local_path) catch {}; + + std.Io.Dir.writeFile(.cwd(), io, .{ + .sub_path = local_path, + .data = daemon_binary, + }) catch |err| { + std.log.scoped(.PhiDevice).err("Failed to write embedded Phi host daemon: {s}", .{@errorName(err)}); + return VkError.InitializationFailed; + }; + + const launch_command = std.fmt.allocPrint( + allocator, + "chmod +x {s} && (nohup {s} --unlink-on-start >/tmp/phi_device_host.log 2>&1 #include -static int HandleHello(scif_epd_t endpoint, const PhiMessageHeader* header) +static int HandleHello(PhiEndpoint endpoint, const PhiMessageHeader* header) { PhiHelloRequest request; PhiHelloReply reply = { @@ -32,41 +32,25 @@ static int HandleHello(scif_epd_t endpoint, const PhiMessageHeader* header) return SendReply(endpoint, header, &reply, sizeof(reply)); } -scif_epd_t StartDaemon() +PhiEndpoint StartDaemon(void) { PhiLogInfo("Starting the daemon..."); - scif_epd_t endpoint = scif_open(); - if(endpoint < 0) - { - PhiLogError("Failed to create SCIF endpoint"); - return 0; - } - - if(scif_bind(endpoint, PHI_SCIF_PORT) < 0) - { - PhiLogError("Failed to bind SCIF port"); - scif_close(endpoint); - return 0; - } - - if(scif_listen(endpoint, 16) < 0) - { - PhiLogError("Could not listen to SCIF port"); - scif_close(endpoint); - return 0; - } + PhiEndpoint endpoint = PhiTransportListen(PHI_TRANSPORT_PORT); + if(endpoint == PHI_ENDPOINT_INVALID) + PhiLogError("Could not listen on the Phi transport"); + PhiLogInfo("Daemon started"); return endpoint; } -void ShutdownDaemon(scif_epd_t endpoint) +void ShutdownDaemon(PhiEndpoint endpoint) { - PhiLogInfo("Shuting down the daemon..."); - scif_close(endpoint); + PhiLogInfo("Shutting down the daemon..."); + PhiTransportClose(endpoint); } -int HandlePacket(scif_epd_t endpoint) +int HandlePacket(PhiEndpoint endpoint) { for(;;) { @@ -123,14 +107,14 @@ int HandlePacket(scif_epd_t endpoint) } } -int ReadAll(scif_epd_t endpoint, void* data, size_t size) +int ReadAll(PhiEndpoint endpoint, void* data, size_t size) { uint8_t* bytes = data; size_t offset = 0; while(offset < size) { - int got = scif_recv(endpoint, bytes + offset, size - offset, SCIF_RECV_BLOCK); + ssize_t got = PhiTransportReceive(endpoint, bytes + offset, size - offset); if(got <= 0) return -1; offset += (size_t)got; @@ -139,14 +123,14 @@ int ReadAll(scif_epd_t endpoint, void* data, size_t size) return 0; } -int WriteAll(scif_epd_t endpoint, const void* data, size_t size) +int WriteAll(PhiEndpoint endpoint, const void* data, size_t size) { const uint8_t* bytes = data; size_t offset = 0; while(offset < size) { - int sent = scif_send(endpoint, (void*)(bytes + offset), size - offset, SCIF_SEND_BLOCK); + ssize_t sent = PhiTransportSend(endpoint, bytes + offset, size - offset); if(sent <= 0) return -1; offset += (size_t)sent; @@ -155,7 +139,7 @@ int WriteAll(scif_epd_t endpoint, const void* data, size_t size) return 0; } -int SendReply(scif_epd_t endpoint, const PhiMessageHeader* request, const void* payload, uint64_t payload_size) +int SendReply(PhiEndpoint endpoint, const PhiMessageHeader* request, const void* payload, uint64_t payload_size) { PhiMessageHeader reply = { .magic = PHI_PROTOCOL_MAGIC, @@ -171,7 +155,7 @@ int SendReply(scif_epd_t endpoint, const PhiMessageHeader* request, const void* return WriteAll(endpoint, payload, (size_t)payload_size); } -int SendStatus(scif_epd_t endpoint, const PhiMessageHeader* request, PhiStatus status) +int SendStatus(PhiEndpoint endpoint, const PhiMessageHeader* request, PhiStatus status) { PhiFreeMemoryReply reply = { .result = { @@ -183,7 +167,7 @@ int SendStatus(scif_epd_t endpoint, const PhiMessageHeader* request, PhiStatus s return SendReply(endpoint, request, &reply, sizeof(reply)); } -int DrainPayload(scif_epd_t endpoint, uint64_t size) +int DrainPayload(PhiEndpoint endpoint, uint64_t size) { uint8_t buffer[256]; diff --git a/src/phi/mic/Daemon.h b/src/phi/mic/Daemon.h index 82bcd62..e70dd96 100644 --- a/src/phi/mic/Daemon.h +++ b/src/phi/mic/Daemon.h @@ -3,18 +3,17 @@ #include -#include - #include +#include -scif_epd_t StartDaemon(); -void ShutdownDaemon(scif_epd_t endpoint); +PhiEndpoint StartDaemon(void); +void ShutdownDaemon(PhiEndpoint endpoint); -int DrainPayload(scif_epd_t endpoint, uint64_t size); -int HandlePacket(scif_epd_t endpoint); -int ReadAll(scif_epd_t endpoint, void* data, size_t size); -int SendReply(scif_epd_t endpoint, const PhiMessageHeader* request, const void* payload, uint64_t payload_size); -int SendStatus(scif_epd_t endpoint, const PhiMessageHeader* request, PhiStatus status); -int WriteAll(scif_epd_t endpoint, const void* data, size_t size); +int DrainPayload(PhiEndpoint endpoint, uint64_t size); +int HandlePacket(PhiEndpoint endpoint); +int ReadAll(PhiEndpoint endpoint, void* data, size_t size); +int SendReply(PhiEndpoint endpoint, const PhiMessageHeader* request, const void* payload, uint64_t payload_size); +int SendStatus(PhiEndpoint endpoint, const PhiMessageHeader* request, PhiStatus status); +int WriteAll(PhiEndpoint endpoint, const void* data, size_t size); #endif diff --git a/src/phi/mic/Logger.c b/src/phi/mic/Logger.c index 9dd3b5e..cd1858e 100644 --- a/src/phi/mic/Logger.c +++ b/src/phi/mic/Logger.c @@ -84,6 +84,7 @@ void PhiLog(PhiLogLevel level, const char* fmt, const char* file, const char* fu va_end(argptr); fputc('\n', out); + fflush(out); if(level == PHI_LOG_LEVEL_FATAL) { diff --git a/src/phi/mic/Memory.c b/src/phi/mic/Memory.c index 863eae0..387ad7a 100644 --- a/src/phi/mic/Memory.c +++ b/src/phi/mic/Memory.c @@ -3,7 +3,7 @@ #include #include -int HandleAllocMemory(scif_epd_t endpoint, const PhiMessageHeader* header) +int HandleAllocMemory(PhiEndpoint endpoint, const PhiMessageHeader* header) { PhiAllocMemoryRequest request; PhiAllocMemoryReply reply = { @@ -42,7 +42,7 @@ int HandleAllocMemory(scif_epd_t endpoint, const PhiMessageHeader* header) return SendReply(endpoint, header, &reply, sizeof(reply)); } -int HandleFreeMemory(scif_epd_t endpoint, const PhiMessageHeader* header) +int HandleFreeMemory(PhiEndpoint endpoint, const PhiMessageHeader* header) { PhiFreeMemoryRequest request; PhiFreeMemoryReply reply = { diff --git a/src/phi/mic/Memory.h b/src/phi/mic/Memory.h index 7832183..add5a5c 100644 --- a/src/phi/mic/Memory.h +++ b/src/phi/mic/Memory.h @@ -3,7 +3,7 @@ #include -int HandleAllocMemory(scif_epd_t endpoint, const PhiMessageHeader* header); -int HandleFreeMemory(scif_epd_t endpoint, const PhiMessageHeader* header); +int HandleAllocMemory(PhiEndpoint endpoint, const PhiMessageHeader* header); +int HandleFreeMemory(PhiEndpoint endpoint, const PhiMessageHeader* header); #endif diff --git a/src/phi/mic/Transport.c b/src/phi/mic/Transport.c new file mode 100644 index 0000000..fc340c2 --- /dev/null +++ b/src/phi/mic/Transport.c @@ -0,0 +1,109 @@ +#include + +#ifdef PHI_HOST_EMULATION + +#include +#include +#include +#include + +static struct sockaddr_in PhiLoopbackAddress(uint16_t port) +{ + struct sockaddr_in address = { + .sin_family = AF_INET, + .sin_port = htons(port), + .sin_addr = { + .s_addr = htonl(INADDR_LOOPBACK), + }, + }; + return address; +} + +PhiEndpoint PhiTransportAccept(PhiEndpoint endpoint) +{ + return accept(endpoint, NULL, NULL); +} + +int PhiTransportClose(PhiEndpoint endpoint) +{ + return close(endpoint); +} + +PhiEndpoint PhiTransportListen(uint16_t port) +{ + PhiEndpoint endpoint = socket(AF_INET, SOCK_STREAM, 0); + if(endpoint == PHI_ENDPOINT_INVALID) + return PHI_ENDPOINT_INVALID; + + const int reuse_address = 1; + if(setsockopt(endpoint, SOL_SOCKET, SO_REUSEADDR, &reuse_address, sizeof(reuse_address)) < 0) + { + PhiTransportClose(endpoint); + return PHI_ENDPOINT_INVALID; + } + + const struct sockaddr_in address = PhiLoopbackAddress(port); + if(bind(endpoint, (const struct sockaddr*)&address, sizeof(address)) < 0 || listen(endpoint, 16) < 0) + { + PhiTransportClose(endpoint); + return PHI_ENDPOINT_INVALID; + } + + return endpoint; +} + +ssize_t PhiTransportReceive(PhiEndpoint endpoint, void* data, size_t size) +{ + return recv(endpoint, data, size, 0); +} + +ssize_t PhiTransportSend(PhiEndpoint endpoint, const void* data, size_t size) +{ +#ifdef MSG_NOSIGNAL + return send(endpoint, data, size, MSG_NOSIGNAL); +#else + return send(endpoint, data, size, 0); +#endif +} + +#else + +PhiEndpoint PhiTransportAccept(PhiEndpoint endpoint) +{ + struct scif_portID peer; + PhiEndpoint client = PHI_ENDPOINT_INVALID; + if(scif_accept(endpoint, &peer, &client, SCIF_ACCEPT_SYNC) < 0) + return PHI_ENDPOINT_INVALID; + return client; +} + +int PhiTransportClose(PhiEndpoint endpoint) +{ + return scif_close(endpoint); +} + +PhiEndpoint PhiTransportListen(uint16_t port) +{ + PhiEndpoint endpoint = scif_open(); + if(endpoint == PHI_ENDPOINT_INVALID) + return PHI_ENDPOINT_INVALID; + + if(scif_bind(endpoint, port) < 0 || scif_listen(endpoint, 16) < 0) + { + PhiTransportClose(endpoint); + return PHI_ENDPOINT_INVALID; + } + return endpoint; +} + +ssize_t PhiTransportReceive(PhiEndpoint endpoint, void* data, size_t size) +{ + return scif_recv(endpoint, data, size, SCIF_RECV_BLOCK); +} + +ssize_t PhiTransportSend(PhiEndpoint endpoint, const void* data, size_t size) +{ + return scif_send(endpoint, (void*)data, size, SCIF_SEND_BLOCK); +} + +#endif diff --git a/src/phi/mic/Transport.h b/src/phi/mic/Transport.h new file mode 100644 index 0000000..edf23c1 --- /dev/null +++ b/src/phi/mic/Transport.h @@ -0,0 +1,24 @@ +#ifndef APE_PHI_TRANSPORT_H +#define APE_PHI_TRANSPORT_H + +#include +#include +#include + +#ifdef PHI_HOST_EMULATION +typedef int PhiEndpoint; +#else +#include +typedef scif_epd_t PhiEndpoint; +#endif + +#define PHI_ENDPOINT_INVALID ((PhiEndpoint) - 1) + +PhiEndpoint PhiTransportAccept(PhiEndpoint endpoint); +int PhiTransportClose(PhiEndpoint endpoint); + +PhiEndpoint PhiTransportListen(uint16_t port); +ssize_t PhiTransportReceive(PhiEndpoint endpoint, void* data, size_t size); +ssize_t PhiTransportSend(PhiEndpoint endpoint, const void* data, size_t size); + +#endif diff --git a/src/phi/mic/main.c b/src/phi/mic/main.c index 81cef18..935ff04 100644 --- a/src/phi/mic/main.c +++ b/src/phi/mic/main.c @@ -2,24 +2,37 @@ #include #include +#ifdef PHI_HOST_EMULATION +#include +#include +#endif + #include #include static void* HandleClient(void* const argument) { - scif_epd_t client = (scif_epd_t)(intptr_t)argument; + PhiEndpoint client = (PhiEndpoint)(intptr_t)argument; (void)HandlePacket(client); - scif_close(client); + PhiTransportClose(client); return NULL; } -int main(void) +int main(int argc, char** argv) { - scif_epd_t endpoint = StartDaemon(); +#ifdef PHI_HOST_EMULATION + if(argc == 2 && strcmp(argv[1], "--unlink-on-start") == 0) + (void)unlink(argv[0]); +#else + (void)argc; + (void)argv; +#endif + + PhiEndpoint endpoint = StartDaemon(); pthread_attr_t client_thread_attributes; - if(endpoint == 0) + if(endpoint == PHI_ENDPOINT_INVALID) return 1; if(pthread_attr_init(&client_thread_attributes) != 0 || @@ -32,22 +45,23 @@ int main(void) for(;;) { - struct scif_portID peer; - scif_epd_t client; + PhiEndpoint client = PhiTransportAccept(endpoint); - if(scif_accept(endpoint, &peer, &client, SCIF_ACCEPT_SYNC) < 0) + if(client == PHI_ENDPOINT_INVALID) { if(errno == EINTR) continue; - PhiLogError("Could not accept SCIF connection"); + PhiLogError("Could not accept transport connection"); break; } + PhiLogInfo("Host connected to the daemon"); + pthread_t client_thread; if(pthread_create(&client_thread, &client_thread_attributes, HandleClient, (void*)(intptr_t)client) != 0) { - PhiLogError("Could not create SCIF client thread"); - scif_close(client); + PhiLogError("Could not create transport client thread"); + PhiTransportClose(client); } } diff --git a/src/phi/mic_stub.zig b/src/phi/mic_stub.zig new file mode 100644 index 0000000..d566e45 --- /dev/null +++ b/src/phi/mic_stub.zig @@ -0,0 +1,3 @@ +pub const Device = struct {}; + +pub fn unload() void {} diff --git a/src/phi/shared/Protocol.h b/src/phi/shared/Protocol.h index 31b8ec6..a93af13 100644 --- a/src/phi/shared/Protocol.h +++ b/src/phi/shared/Protocol.h @@ -8,6 +8,10 @@ #define PHI_PROTOCOL_VERSION 1u #define PHI_SCIF_PORT 43616u +#ifndef PHI_TRANSPORT_PORT +#define PHI_TRANSPORT_PORT PHI_SCIF_PORT +#endif + typedef enum PhiPacketType { PHI_PACKET_HELLO = 1,