Skip to content
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#pragma once

#include <AttributeGraph/AGBase.h>

#if TARGET_OS_MAC

#include <CoreFoundation/CFURL.h>

typedef void *AGDebugServerRef AG_SWIFT_STRUCT AG_SWIFT_NAME(DebugServer);

typedef AG_OPTIONS(uint32_t, AGDebugServerOptions){
AGDebugServerOptionsEnabled = 1 << 0,
AGDebugServerOptionsNetworkInterface = 1 << 1,
} AG_SWIFT_NAME(DebugServer.Options);

typedef struct AG_SWIFT_NAME(DebugServer.MessageHeader) AGDebugServerMessageHeader {
uint32_t token;
uint32_t reserved1;
uint32_t body_length;
uint32_t reserved2;
} AGDebugServerMessageHeader;

AG_ASSUME_NONNULL_BEGIN
AG_IMPLICIT_BRIDGING_ENABLED

AG_EXTERN_C_BEGIN

AG_EXPORT
AG_REFINED_FOR_SWIFT
void AGDebugServerStart(AGDebugServerOptions options) AG_SWIFT_NAME(DebugServer.start(options:));

AG_EXPORT
AG_REFINED_FOR_SWIFT
void AGDebugServerStop(void) AG_SWIFT_NAME(DebugServer.stop());

AG_EXPORT
AG_REFINED_FOR_SWIFT
void AGDebugServerRun(uint32_t timeout) AG_SWIFT_NAME(DebugServer.run(timeout:));

AG_EXPORT
AG_REFINED_FOR_SWIFT
CFURLRef _Nullable AGDebugServerCopyURL(void) AG_SWIFT_NAME(getter:DebugServer.url());

AG_EXTERN_C_END

AG_IMPLICIT_BRIDGING_DISABLED
AG_ASSUME_NONNULL_END

#endif
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <AttributeGraph/AGChangedValue.h>
#include <AttributeGraph/AGClosure.h>
#include <AttributeGraph/AGComparison.h>
#include <AttributeGraph/AGDebugServer.h>
#include <AttributeGraph/AGDescription.h>
#include <AttributeGraph/AGGraph.h>
#include <AttributeGraph/AGGraphCounterQueryType.h>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#pragma once

#include <AttributeGraph/AGBase.h>

#if TARGET_OS_MAC

#include <CoreFoundation/CFURL.h>

typedef void *AGDebugServerRef AG_SWIFT_STRUCT AG_SWIFT_NAME(DebugServer);

typedef AG_OPTIONS(uint32_t, AGDebugServerOptions){
AGDebugServerOptionsEnabled = 1 << 0,
AGDebugServerOptionsNetworkInterface = 1 << 1,
} AG_SWIFT_NAME(DebugServer.Options);

typedef struct AG_SWIFT_NAME(DebugServer.MessageHeader) AGDebugServerMessageHeader {
uint32_t token;
uint32_t reserved1;
uint32_t body_length;
uint32_t reserved2;
} AGDebugServerMessageHeader;

AG_ASSUME_NONNULL_BEGIN
AG_IMPLICIT_BRIDGING_ENABLED

AG_EXTERN_C_BEGIN

AG_EXPORT
AG_REFINED_FOR_SWIFT
void AGDebugServerStart(AGDebugServerOptions options) AG_SWIFT_NAME(DebugServer.start(options:));

AG_EXPORT
AG_REFINED_FOR_SWIFT
void AGDebugServerStop(void) AG_SWIFT_NAME(DebugServer.stop());

AG_EXPORT
AG_REFINED_FOR_SWIFT
void AGDebugServerRun(uint32_t timeout) AG_SWIFT_NAME(DebugServer.run(timeout:));

AG_EXPORT
AG_REFINED_FOR_SWIFT
CFURLRef _Nullable AGDebugServerCopyURL(void) AG_SWIFT_NAME(getter:DebugServer.url());

AG_EXTERN_C_END

AG_IMPLICIT_BRIDGING_DISABLED
AG_ASSUME_NONNULL_END

#endif
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <AttributeGraph/AGChangedValue.h>
#include <AttributeGraph/AGClosure.h>
#include <AttributeGraph/AGComparison.h>
#include <AttributeGraph/AGDebugServer.h>
#include <AttributeGraph/AGDescription.h>
#include <AttributeGraph/AGGraph.h>
#include <AttributeGraph/AGGraphCounterQueryType.h>
Expand Down
149 changes: 149 additions & 0 deletions Sources/ComputeCxx/Debug/Connection.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
#include "DebugServer.h"

#if TARGET_OS_MAC

#include <dispatch/dispatch.h>

#include <Utilities/ObjCPointer.h>

namespace IAG {

DebugServer::Connection::Connection(DebugServer *server, int socket) : _server(server), _socket(socket) {
dispatch_source_t event_source =
dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, socket, 0, dispatch_get_main_queue());
dispatch_set_context(event_source, this);
dispatch_source_set_event_handler_f(event_source, handler);
dispatch_resume(event_source);
_event_source = util::adopt_objc(event_source);
}

DebugServer::Connection::~Connection() {
dispatch_source_set_event_handler_f(_event_source.get(), nullptr);
dispatch_set_context(_event_source.get(), nullptr);
close(_socket);
}

namespace {

bool blocking_read(int socket_fd, void *buffer, size_t size) {
if (size == 0) {
return true;
}

size_t total_read = 0;
char *bytes = static_cast<char *>(buffer);

while (total_read < size) {
ssize_t bytes_read = read(socket_fd, bytes + total_read, size - total_read);

if (bytes_read > 0) {
total_read += bytes_read;
} else if (bytes_read == 0) {
// Socket closed
return false;
} else {
if (errno == EINTR) {
continue; // Interrupted, retry
}
#if DEBUG
assert(errno != EAGAIN && errno != EWOULDBLOCK); // blocking mode shouldn't encounter these errors
#else
if (errno == EAGAIN || errno == EWOULDBLOCK) {
// Non-blocking mode: No data available, retry or handle accordingly
continue;
}
#endif
perror("IAGDebugServer: read");
return false;
}
}

return true;
}

bool blocking_write(int socket_fd, const void *buffer, size_t size) {
if (size == 0) {
return true;
}

size_t total_written = 0;
const char *bytes = static_cast<const char *>(buffer);

while (total_written < size) {
ssize_t bytes_written = write(socket_fd, bytes + total_written, size - total_written);

if (bytes_written > 0) {
total_written += bytes_written;
} else if (bytes_written == 0) {
return false; // Unexpected write failure
} else {
if (errno == EINTR) {
continue; // Interrupted, retry
} else if (errno == EAGAIN || errno == EWOULDBLOCK) {
continue; // Non-blocking mode: Retry or handle accordingly
} else {
perror("IAGDebugServer: write");
return false;
}
}
}

return true;
}

} // namespace

void DebugServer::Connection::handler(void *context) {
Connection *connection = reinterpret_cast<Connection *>(context);

uint8_t header_bytes[sizeof(IAGDebugServerMessageHeader)];
if (!blocking_read(connection->_socket, header_bytes, sizeof(header_bytes))) {
connection->_server->close_connection(connection);
return;
}

IAGDebugServerMessageHeader *header = reinterpret_cast<IAGDebugServerMessageHeader *>(header_bytes);
if (header->token != connection->_server->_token) {
connection->_server->close_connection(connection);
return;
}

CFIndex length = header->body_length;
CFMutableDataRef request_data = CFDataCreateMutable(kCFAllocatorDefault, length);
if (!request_data) {
connection->_server->close_connection(connection);
return;
}

CFDataSetLength(request_data, length);
void *request_bytes = CFDataGetMutableBytePtr(request_data);

if (blocking_read(connection->_socket, request_bytes, length)) {
CFDataRef response_data = connection->_server->receive(connection, header, request_data);
if (response_data) {
CFIndex response_length = CFDataGetLength(response_data);
if (response_length >> 32 == 0) {
header->body_length = (uint32_t)response_length;
if (blocking_write(connection->_socket, reinterpret_cast<const void *>(header),
sizeof(IAGDebugServerMessageHeader))) {
const unsigned char *response_bytes = CFDataGetBytePtr(response_data);
if (blocking_write(connection->_socket, response_bytes, response_length)) {
connection = nullptr; // do not close connection
}
}
}

CFRelease(response_data);
}
}

CFRelease(request_data);

if (connection) {
connection->_server->close_connection(connection);
}
}

} // namespace IAG

#endif
Loading