Here's the summary of the change

Summary: macOS Threading Fixes for Socket Server IntegrationOverview

This document summarizes the changes made to VirtualT to allow the GUI to
run and receive input from the Socket Server without crashing on macOS.
Root Cause

On macOS, FLTK (the GUI library) is *not thread-safe* and requires all GUI
operations to run on the main thread. The socket server runs in a separate
background thread (gRemoteThread), and when remote commands tried to call
FLTK functions or manipulate GUI state from the socket thread, it caused
crashes.
Changes Made1. *src/remote.cpp* - Main Threading FixesA. Added macOS
Dispatch Infrastructure (lines 112-129)

#ifdef __APPLE__
#include <dispatch/dispatch.h>

static void reset_dispatch(void* data)
{
    (void) data;
    remote_reset();
}

static void cold_boot_dispatch(void* data)
{
    (void) data;
    remote_cold_boot();
}
#endif


   - Wrapper functions to dispatch operations to the main thread
   - Uses macOS Grand Central Dispatch (GCD) for thread synchronization

B. Fixed cmd_reset() (lines 686-697)

std::string cmd_reset(ServerSocket& sock)
{
#ifdef __APPLE__
    if (!pthread_main_np())
    {
        dispatch_sync_f(dispatch_get_main_queue(), NULL, reset_dispatch);
        return gOk;
    }
#endif
    remote_reset();
    return gOk;
}


   - Checks if running on main thread using pthread_main_np()
   - If not on main thread, dispatches to main queue synchronously
   - Prevents crashes when reset command comes from socket server

C. Fixed cmd_cold_boot() (lines 704-715)

std::string cmd_cold_boot(ServerSocket& sock)
{
#ifdef __APPLE__
    if (!pthread_main_np())
    {
        dispatch_sync_f(dispatch_get_main_queue(), NULL, cold_boot_dispatch);
        return gOk;
    }
#endif
    remote_cold_boot();
    return gOk;
}


   - Same pattern as cmd_reset()
   - Ensures cold boot operations run on main thread

D. Fixed key_delay() (lines 1669-1687)

void key_delay(void)
{
#ifdef __APPLE__
    if (!pthread_main_np())
    {
        while (gSimKey != 0)
            usleep(1000);
        while (gDelayUpdateKeys)
            usleep(1000);
        return;
    }
#endif
    while (gSimKey != 0)
        Fl::wait(0.001);

    while (gDelayUpdateKeys)
        Fl::wait(0.001);
}


   - *Critical fix*: Fl::wait() cannot be called from non-main thread
   - Uses usleep() instead when on background thread
   - Prevents FLTK thread-safety violations during key simulation

E. Refactored cmd_key() (lines 1849, 1964-1970)

static std::string cmd_key_impl(std::string& args)
{
    // ... implementation ...
}

std::string cmd_key(ServerSocket& sock, std::string& args)
{
    (void)sock;
    return cmd_key_impl(args);
}


   - Separated implementation from socket handling
   - Cleaner code organization

F. Socket Data Safety (lines 3247-3251)

len = gSocket.openSock.recv(sockData, sizeof(sockData));
if (len <= 0)
    continue;
if (len >= (int) sizeof(sockData))
    len = sizeof(sockData) - 1;
sockData[len] = 0;


   - Added null termination to received socket data
   - Prevents buffer overruns and undefined behavior

G. Added Header (line 51)

#include <unistd.h>


   - Required for usleep() and POSIX functions

2. *src/display.cpp* - Keyboard Input Fix (Separate Issue)

   - Added reverse-mapping for shifted special characters on macOS
   - This was a separate bug unrelated to socket server threading
   - Fixed: Shift+' producing ", Shift+1 producing !, etc.

Technical DetailsWhy These Changes Were Necessary

   1. *FLTK Thread Safety*: FLTK's design requires all GUI operations on
   the main thread
   2. *Socket Server Architecture*: Runs in background thread (pthread_t
   gRemoteThread)
   3. *Remote Commands*: When commands arrive via socket, they execute in
   the socket thread
   4. *GUI Manipulation*: Commands like reset, cold_boot, and key manipulate
   GUI state

The Threading Model

Main Thread (GUI)
    └─ FLTK Event Loop
    └─ Display rendering
    └─ Keyboard input handling

Background Thread (Socket Server)
    └─ Accept connections
    └─ Receive commands
    └─ Execute commands
        └─ Must dispatch GUI operations back to main thread ← Fix applied here

macOS Specific APIs Used

   - pthread_main_np(): Check if currently on main thread
   - dispatch_sync_f(): Synchronously execute function on main queue
   - dispatch_get_main_queue(): Get reference to main thread's dispatch
   queue
   - usleep(): Sleep without blocking FLTK event loop

Files Modified

   - src/remote.cpp - Main threading fixes
   - src/m100emu.c - Debug bridge cleanup
   - src/display.cpp - Keyboard input fix (unrelated)


On Fri, Dec 26, 2025 at 4:08 PM B9 <[email protected]> wrote:

>
>
> On December 25, 2025 2:54:55 PM PST, Kenneth Pettit <[email protected]>
> wrote:
> >On 12/23/25 2:39 PM, George M. Rimakis wrote:
> >>
> >> He (please bear with my anthropomorphizing of the LLM), found out that
> somehow it was causing the GUI to crash.
> >>
> >> I honestly don’t exactly know what he did, but he modified the code so
> that he was able to safely push keys at the same time as a user in the GUI,
> without the app crashing.
> >>
> >Would be really interested to see what changes Claude made to resolve the
> GUI crash / deadlock / garbled output if you are up to sharing them.
>
> For the sake of science, I'm glad to see George has let Claude file the
> bug report instead of typing it up himself. Understanding the code — or
> trying to — would end George's experiment in "vibe coding" in which one
> "embraces exponentials and forgets the code exists".
>
> I'm fascinated seeing a hybrid approach happening in real-life: We have a
> vibe coder making a patch for existing code that an expert coder will
> examine.
>
> Clearly it saved George, the vibe coder, time and effort. If he had to
> understand the original program, identify the bug, and learn enough to
> write a patch, he  probably wouldn't have even tried.
>
> Now, the question is: How much time and effort will it cost Ken, the
> expert programmer, to handle the AI generated report? Would it have taken
> Ken more or less time if he had used Claude interactively to fix the bug?
>
> Bug reports with patches have traditionally been very helpful, but there
> are costs, especially with AI. Does Claude's description match the code
> generated? Has it identified the actual source of the error? Is it the
> correct fix? Does the patch break anything else? Does it add extraneous
> changes? Does it take an incremental approach when refactoring would be
> more appropriate (or vice versa)? Are the changes written in a way that
> will be easy to understand and maintain in the future?
>
> Ken, if you don't mind, please let us know what your experience is and if
> you would welcome more patches from vibe coders in the future.
>
> --b9
>
>

Reply via email to