• Russ Cox's avatar
    runtime, syscall: work around FreeBSD/amd64 kernel bug · 555da73c
    Russ Cox authored
    The kernel implementation of the fast system call path,
    the one invoked by the SYSCALL instruction, is broken for
    restarting system calls. A C program demonstrating this is below.
    
    Change the system calls to use INT $0x80 instead, because
    that (perhaps slightly slower) system call path actually works.
    
    I filed http://www.freebsd.org/cgi/query-pr.cgi?pr=182161.
    
    The C program demonstrating that it is FreeBSD's fault is below.
    It reports the same "Bad address" failures from wait.
    
    #include <sys/time.h>
    #include <sys/signal.h>
    #include <pthread.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    
    static void handler(int);
    static void* looper(void*);
    
    int
    main(void)
    {
            int i;
            struct sigaction sa;
            pthread_cond_t cond;
            pthread_mutex_t mu;
    
            memset(&sa, 0, sizeof sa);
            sa.sa_handler = handler;
            sa.sa_flags = SA_RESTART;
            memset(&sa.sa_mask, 0xff, sizeof sa.sa_mask);
            sigaction(SIGCHLD, &sa, 0);
    
            for(i=0; i<2; i++)
                    pthread_create(0, 0, looper, 0);
    
            pthread_mutex_init(&mu, 0);
            pthread_mutex_lock(&mu);
            pthread_cond_init(&cond, 0);
            for(;;)
                    pthread_cond_wait(&cond, &mu);
    
            return 0;
    }
    
    static void
    handler(int sig)
    {
    }
    
    int
    mywait4(int pid, int *stat, int options, struct rusage *rusage)
    {
            int result;
    
            asm("movq %%rcx, %%r10; syscall"
                    : "=a" (result)
                    : "a" (7),
                      "D" (pid),
                      "S" (stat),
                      "d" (options),
                      "c" (rusage));
    }
    
    static void*
    looper(void *v)
    {
            int pid, stat, out;
            struct rusage rusage;
    
            for(;;) {
                    if((pid = fork()) == 0)
                            _exit(0);
                    out = mywait4(pid, &stat, 0, &rusage);
                    if(out != pid) {
                            printf("wait4 returned %d\n", out);
                    }
            }
    }
    
    Fixes #6372.
    
    R=golang-dev, bradfitz
    CC=golang-dev
    https://golang.org/cl/13582047
    555da73c
Name
Last commit
Last update
api Loading commit data...
doc Loading commit data...
include Loading commit data...
lib Loading commit data...
misc Loading commit data...
src Loading commit data...
test Loading commit data...
.hgignore Loading commit data...
.hgtags Loading commit data...
AUTHORS Loading commit data...
CONTRIBUTORS Loading commit data...
LICENSE Loading commit data...
PATENTS Loading commit data...
README Loading commit data...
favicon.ico Loading commit data...
robots.txt Loading commit data...