
Hey guys, I was experienced at C about 20 years ago, since 15 years I'm coding with Ruby. I now need to write a Ruby C extension, and I fail with just calling simple commands like rb_p. I try to integrate a fast C websocket server into my quiz website (Rails cable is too slow) In order to communicate I need a UNIX socket in C to receive commands from the Rails server. I used the xcode standard compiler, and also tried homebrew gcc-14 It compiles fine all set up with extconf.rb When I call QbGameServer.init, it creates the server, and after a second wait tries to connect. The c thread is created and gets the message, However when I call rb_p or rb_funcall it hangs (M2) or segfauls (Intel) What do I do wrong? Thanks a lot! Martin I created a QbGameServerModule, extending my QbGameServer and call module QbGameServer SOCKET_PATH="/tmp/sock/qb-game-server" extend QbGameServerModule def self.init # Start the server (non-blocking) self.start_rpc(SOCKET_PATH) do |message| puts "Received from client: #{message}" end sleep 1 send_socket end def self.send_socket # Create a new Unix socket socket = UNIXSocket.new(SOCKET_PATH) # Example data to send to the server (Ruby hash converted to JSON) data_to_send = { message: "Hello, server!", timestamp: Time.now.to_s }.to_json # Send the JSON data to the server puts "Sent to server: #{data_to_send}" socket.puts(data_to_send) # Read the response from the server response = socket.gets.chomp # Read the response from the socket puts "Received from server: #{response}" ensure # Close the socket connection after the communication is done socket.close if socket end end On the C side I have the ext/qb_game_server/qb_game_server.c #include "ruby.h" #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #include <unistd.h> #include <pthread.h> #include <string.h> #define MAX_CLIENTS 10 #define BUFFER_SIZE 1024 VALUE QbGameServerModule = Qnil; static VALUE rpc_proc = Qnil; static char socket_file_path[108]; // Maximum length for UNIX domain socket path void *client_handler(void *sock) { int client_socket = *(int *)sock; char buffer[BUFFER_SIZE]; ssize_t bytes_read; while ((bytes_read = read(client_socket, buffer, sizeof(buffer) - 1)) > 0) { buffer[bytes_read] = '\0'; printf("Received C %s\n", buffer); VALUE arg = rb_str_new_cstr(buffer); // rb_gc_register_address(&arg); printf("1\n"); // DOES REACH // rb_gc(); printf("2\n"); // DOES REACH rb_p(arg); // ***** DOES NOT REACH HERE***** // On the osx sonoma M2 it just hangs, on osx Intel Catalina it shows a segfault printf("3\n"); // rb_gc_unregister_address(&arg); // rb_funcall(rpc_proc, rb_intern("call"), 1, arg); } close(client_socket); return NULL; } void *server_thread(void *arg) { int server_socket = socket(AF_UNIX, SOCK_STREAM, 0); struct sockaddr_un server_addr; int client_sockets[MAX_CLIENTS]; pthread_t threads[MAX_CLIENTS]; int client_count = 0; memset(&server_addr, 0, sizeof(server_addr)); server_addr.sun_family = AF_UNIX; strncpy(server_addr.sun_path, socket_file_path, sizeof(server_addr.sun_path) - 1); unlink(socket_file_path); bind(server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)); listen(server_socket, MAX_CLIENTS); while (1) { client_sockets[client_count] = accept(server_socket, NULL, NULL); pthread_create(&threads[client_count], NULL, client_handler, &client_sockets[client_count]); client_count++; } close(server_socket); return NULL; } static VALUE start_rpc(VALUE self, VALUE socket_file) { Check_Type(socket_file, T_STRING); strncpy(socket_file_path, StringValueCStr(socket_file), sizeof(socket_file_path) - 1); if (rb_block_given_p()) { rpc_proc = rb_block_proc(); } else { rb_raise(rb_eArgError, "A block must be provided as a callback"); } pthread_t server_tid; pthread_create(&server_tid, NULL, server_thread, NULL); return Qnil; } void Init_qb_game_server() { printf("Init QbGameServerModule\n"); QbGameServerModule = rb_define_module("QbGameServerModule"); rb_define_method(QbGameServerModule, "start_rpc", start_rpc, 1); }