• 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
..
cmd Loading commit data...
lib9 Loading commit data...
libbio Loading commit data...
libmach Loading commit data...
pkg Loading commit data...
Make.dist Loading commit data...
all.bash Loading commit data...
all.bat Loading commit data...
all.rc Loading commit data...
clean.bash Loading commit data...
clean.bat Loading commit data...
clean.rc Loading commit data...
make.bash Loading commit data...
make.bat Loading commit data...
make.rc Loading commit data...
race.bash Loading commit data...
race.bat Loading commit data...
run.bash Loading commit data...
run.bat Loading commit data...
run.rc Loading commit data...
sudo.bash Loading commit data...