OiO.lk Blog C++ Win32 child process not flushing stdout until exit
C++

Win32 child process not flushing stdout until exit


I’m starting to write an LSP extension for vscode for my language in C (on windows). I’m having trouble with getting my extremely simple C program to flush stdout when spawned as a child process (vscode does this). When I run the same program directly from the command line, it works as expected. I have a simple python script that simulates the lsp protocol and I see the same behavior here as I do when running under vscode.

Here is the simplest C program I can use to simulate the error. (I had a C++ program that behaved the same way as well with std::cout and friends)

#include <windows.h>
#include <stdio.h>

int main() {
    char buffer[1024];
    // Infinite loop to continuously listen for LSP requests
    // without the loop it works fine. 
    while (1) {

        if (fgets(buffer, 1024, stdin) == NULL) {
            break;
        }

        const char* contentOffset = buffer + 16; // read content value (16 is the size of "Content-Length:"

        char* pEnd;
        size_t len = strtoll(contentOffset, &pEnd, 10) + 1;

        fgets(buffer, 1024, stdin); // read empty line

        // Read the JSON body based on Content-Length
        fgets(buffer, (int32) len, stdin);

        // Process the incoming JSON body (simple echo back for testing)
        // Echo the same JSON body back with the appropriate LSP header
        printf("Content-Length: %d\r\n\r\n%s", (int32_t)len - 1, buffer); // I've also tried fprintf and the windows apis as well, same effect
        // Flush stdout to ensure the message is sent immediately (this seems to have no effect)
        fflush(stdout);
    }
    return 0;
}

And here is a simple python script to simulate the lsp


import subprocess
import time

# Start the C program
process = subprocess.Popen(
    ["path/to/exe"],  
    stdin=subprocess.PIPE,
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE,
    universal_newlines=True,  # Ensure text mode
)

# Function to send LSP request and read response
def send_lsp_request(json_request):
    content_length = len(json_request)

    # Send the LSP-style request
    lsp_message = f"Content-Length: {content_length}\r\n\r\n{json_request}"
    process.stdin.write(lsp_message)
    process.stdin.flush()

    # Allow some time for the C program to respond
    time.sleep(0.1)

    # Read and print the response from stdout
    response = process.stdout.read(1024)
    return response

# Example LSP request
json_request="{"jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {}}"
print('sent')
# Send a request to the C LSP server and print the response
response = send_lsp_request(json_request)
print("Response from C program:\n", response)

I expect the program to behave the same under both conditions. Instead when run with the python script, it prints sent and then hangs forever waiting for the process to put something in stdout which never happens.

If I remove the while loop in the C program, we get the output we expect but I can’t actually do that because the program needs to continue listening for more messages.

I have no idea why this happens. I’ve read something about handles being inherited but I don’t control what vscode does with that and I’d be surprised if the stdio transport supplied by vscode didn’t do the right thing for this. I don’t have other hardware to tell if this is a windows-only issue.

Any insights are incredibly appreciated.



You need to sign in to view this answers

Exit mobile version