X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fum%2Fkernel%2Fsigio_user.c;h=f7b18e157d3509d9b4302b1dc8dfd39c02756630;hb=134734d875a0a48d994ef20b9905209b4b8b6f75;hp=b5ce13d55cd526322814e4727bd4dfb4654bd439;hpb=daddc0d38b3571bed170afa273a49a0eba090c1e;p=linux-2.6.git diff --git a/arch/um/kernel/sigio_user.c b/arch/um/kernel/sigio_user.c index b5ce13d55..f7b18e157 100644 --- a/arch/um/kernel/sigio_user.c +++ b/arch/um/kernel/sigio_user.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -17,8 +16,8 @@ #include "init.h" #include "user.h" #include "kern_util.h" +#include "user_util.h" #include "sigio.h" -#include "helper.h" #include "os.h" /* Changed during early boot */ @@ -26,7 +25,7 @@ int pty_output_sigio = 0; int pty_close_sigio = 0; /* Used as a flag during SIGIO testing early in boot */ -static int got_sigio = 0; +static volatile int got_sigio = 0; void __init handler(int sig) { @@ -45,19 +44,18 @@ static void openpty_cb(void *arg) info->err = 0; if(openpty(&info->master, &info->slave, NULL, NULL, NULL)) - info->err = errno; + info->err = -errno; } void __init check_one_sigio(void (*proc)(int, int)) { struct sigaction old, new; - struct termios tt; struct openpty_arg pty = { .master = -1, .slave = -1 }; - int master, slave, flags; + int master, slave, err; initial_thread_cb(openpty_cb, &pty); if(pty.err){ - printk("openpty failed, errno = %d\n", pty.err); + printk("openpty failed, errno = %d\n", -pty.err); return; } @@ -69,23 +67,14 @@ void __init check_one_sigio(void (*proc)(int, int)) return; } - if(tcgetattr(master, &tt) < 0) - panic("check_sigio : tcgetattr failed, errno = %d\n", errno); - cfmakeraw(&tt); - if(tcsetattr(master, TCSADRAIN, &tt) < 0) - panic("check_sigio : tcsetattr failed, errno = %d\n", errno); + /* Not now, but complain so we now where we failed. */ + err = raw(master); + if (err < 0) + panic("check_sigio : __raw failed, errno = %d\n", -err); - if((flags = fcntl(master, F_GETFL)) < 0) - panic("tty_fds : fcntl F_GETFL failed, errno = %d\n", errno); - - if((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) || - (fcntl(master, F_SETOWN, os_getpid()) < 0)) - panic("check_sigio : fcntl F_SETFL or F_SETOWN failed, " - "errno = %d\n", errno); - - if((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0)) - panic("check_sigio : fcntl F_SETFL failed, errno = %d\n", - errno); + err = os_sigio_async(master, slave); + if(err < 0) + panic("tty_fds : sigio_async failed, err = %d\n", -err); if(sigaction(SIGIO, NULL, &old) < 0) panic("check_sigio : sigaction 1 failed, errno = %d\n", errno); @@ -97,8 +86,8 @@ void __init check_one_sigio(void (*proc)(int, int)) got_sigio = 0; (*proc)(master, slave); - close(master); - close(slave); + os_close_file(master); + os_close_file(slave); if(sigaction(SIGIO, &old, NULL) < 0) panic("check_sigio : sigaction 3 failed, errno = %d\n", errno); @@ -112,25 +101,27 @@ static void tty_output(int master, int slave) printk("Checking that host ptys support output SIGIO..."); memset(buf, 0, sizeof(buf)); - while(write(master, buf, sizeof(buf)) > 0) ; + + while(os_write_file(master, buf, sizeof(buf)) > 0) ; if(errno != EAGAIN) panic("check_sigio : write failed, errno = %d\n", errno); + while(((n = os_read_file(slave, buf, sizeof(buf))) > 0) && !got_sigio) ; - while(((n = read(slave, buf, sizeof(buf))) > 0) && !got_sigio) ; - - if(got_sigio){ + if (got_sigio) { printk("Yes\n"); pty_output_sigio = 1; + } else if (n == -EAGAIN) { + printk("No, enabling workaround\n"); + } else { + panic("check_sigio : read failed, err = %d\n", n); } - else if(errno == EAGAIN) printk("No, enabling workaround\n"); - else panic("check_sigio : read failed, errno = %d\n", errno); } static void tty_close(int master, int slave) { printk("Checking that host ptys support SIGIO on close..."); - close(slave); + os_close_file(slave); if(got_sigio){ printk("Yes\n"); pty_close_sigio = 1; @@ -140,7 +131,8 @@ static void tty_close(int master, int slave) void __init check_sigio(void) { - if(access("/dev/ptmx", R_OK) && access("/dev/ptyp0", R_OK)){ + if((os_access("/dev/ptmx", OS_ACC_R_OK) < 0) && + (os_access("/dev/ptyp0", OS_ACC_R_OK) < 0)){ printk("No pseudo-terminals available - skipping pty SIGIO " "check\n"); return; @@ -189,6 +181,7 @@ static int write_sigio_thread(void *unused) int i, n, respond_fd; char c; + signal(SIGWINCH, SIG_IGN); fds = ¤t_poll; while(1){ n = poll(fds->poll, fds->used, -1); @@ -201,11 +194,10 @@ static int write_sigio_thread(void *unused) p = &fds->poll[i]; if(p->revents == 0) continue; if(p->fd == sigio_private[1]){ - n = read(sigio_private[1], &c, sizeof(c)); + n = os_read_file(sigio_private[1], &c, sizeof(c)); if(n != sizeof(c)) printk("write_sigio_thread : " - "read failed, errno = %d\n", - errno); + "read failed, err = %d\n", -n); tmp = current_poll; current_poll = next_poll; next_poll = tmp; @@ -218,12 +210,14 @@ static int write_sigio_thread(void *unused) (fds->used - i) * sizeof(*fds->poll)); } - n = write(respond_fd, &c, sizeof(c)); + n = os_write_file(respond_fd, &c, sizeof(c)); if(n != sizeof(c)) printk("write_sigio_thread : write failed, " - "errno = %d\n", errno); + "err = %d\n", -n); } } + + return 0; } static int need_poll(int n) @@ -232,7 +226,7 @@ static int need_poll(int n) next_poll.used = n; return(0); } - if(next_poll.poll != NULL) kfree(next_poll.poll); + kfree(next_poll.poll); next_poll.poll = um_kmalloc_atomic(n * sizeof(struct pollfd)); if(next_poll.poll == NULL){ printk("need_poll : failed to allocate new pollfds\n"); @@ -245,6 +239,8 @@ static int need_poll(int n) return(0); } +/* Must be called with sigio_lock held, because it's needed by the marked + * critical section. */ static void update_thread(void) { unsigned long flags; @@ -252,30 +248,30 @@ static void update_thread(void) char c; flags = set_signals(0); - n = write(sigio_private[0], &c, sizeof(c)); + n = os_write_file(sigio_private[0], &c, sizeof(c)); if(n != sizeof(c)){ - printk("update_thread : write failed, errno = %d\n", errno); + printk("update_thread : write failed, err = %d\n", -n); goto fail; } - n = read(sigio_private[0], &c, sizeof(c)); + n = os_read_file(sigio_private[0], &c, sizeof(c)); if(n != sizeof(c)){ - printk("update_thread : read failed, errno = %d\n", errno); + printk("update_thread : read failed, err = %d\n", -n); goto fail; } set_signals(flags); return; fail: - sigio_lock(); + /* Critical section start */ if(write_sigio_pid != -1) os_kill_process(write_sigio_pid, 1); write_sigio_pid = -1; - close(sigio_private[0]); - close(sigio_private[1]); - close(write_sigio_fds[0]); - close(write_sigio_fds[1]); - sigio_unlock(); + os_close_file(sigio_private[0]); + os_close_file(sigio_private[1]); + os_close_file(write_sigio_fds[0]); + os_close_file(write_sigio_fds[1]); + /* Critical section end */ set_signals(flags); } @@ -341,70 +337,103 @@ int ignore_sigio_fd(int fd) return(err); } -static int setup_initial_poll(int fd) +static struct pollfd* setup_initial_poll(int fd) { struct pollfd *p; p = um_kmalloc(sizeof(struct pollfd)); - if(p == NULL){ + if (p == NULL) { printk("setup_initial_poll : failed to allocate poll\n"); - return(-1); + return NULL; } *p = ((struct pollfd) { .fd = fd, .events = POLLIN, .revents = 0 }); - current_poll = ((struct pollfds) { .poll = p, - .used = 1, - .size = 1 }); - return(0); + return p; } void write_sigio_workaround(void) { unsigned long stack; + struct pollfd *p; int err; + int l_write_sigio_fds[2]; + int l_sigio_private[2]; + int l_write_sigio_pid; + /* We call this *tons* of times - and most ones we must just fail. */ sigio_lock(); - if(write_sigio_pid != -1) - goto out; + l_write_sigio_pid = write_sigio_pid; + sigio_unlock(); - err = os_pipe(write_sigio_fds, 1, 1); - if(err){ + if (l_write_sigio_pid != -1) + return; + + err = os_pipe(l_write_sigio_fds, 1, 1); + if(err < 0){ printk("write_sigio_workaround - os_pipe 1 failed, " - "errno = %d\n", -err); - goto out; + "err = %d\n", -err); + return; } - err = os_pipe(sigio_private, 1, 1); - if(err){ - printk("write_sigio_workaround - os_pipe 2 failed, " - "errno = %d\n", -err); + err = os_pipe(l_sigio_private, 1, 1); + if(err < 0){ + printk("write_sigio_workaround - os_pipe 1 failed, " + "err = %d\n", -err); goto out_close1; } - if(setup_initial_poll(sigio_private[1])) + + p = setup_initial_poll(l_sigio_private[1]); + if(!p) goto out_close2; - write_sigio_pid = run_helper_thread(write_sigio_thread, NULL, + sigio_lock(); + + /* Did we race? Don't try to optimize this, please, it's not so likely + * to happen, and no more than once at the boot. */ + if(write_sigio_pid != -1) + goto out_unlock; + + write_sigio_pid = run_helper_thread(write_sigio_thread, NULL, CLONE_FILES | CLONE_VM, &stack, 0); - if(write_sigio_pid < 0) goto out_close2; + if (write_sigio_pid < 0) + goto out_clear; - if(write_sigio_irq(write_sigio_fds[0])) + if (write_sigio_irq(l_write_sigio_fds[0])) goto out_kill; - out: + /* Success, finally. */ + memcpy(write_sigio_fds, l_write_sigio_fds, sizeof(l_write_sigio_fds)); + memcpy(sigio_private, l_sigio_private, sizeof(l_sigio_private)); + + current_poll = ((struct pollfds) { .poll = p, + .used = 1, + .size = 1 }); + sigio_unlock(); return; out_kill: - os_kill_process(write_sigio_pid, 1); + l_write_sigio_pid = write_sigio_pid; + write_sigio_pid = -1; + sigio_unlock(); + /* Going to call waitpid, avoid holding the lock. */ + os_kill_process(l_write_sigio_pid, 1); + goto out_free; + + out_clear: write_sigio_pid = -1; + out_unlock: + sigio_unlock(); + out_free: + kfree(p); out_close2: - close(sigio_private[0]); - close(sigio_private[1]); + os_close_file(l_sigio_private[0]); + os_close_file(l_sigio_private[1]); out_close1: - close(write_sigio_fds[0]); - close(write_sigio_fds[1]); - sigio_unlock(); + os_close_file(l_write_sigio_fds[0]); + os_close_file(l_write_sigio_fds[1]); + return; } int read_sigio_fd(int fd) @@ -412,29 +441,26 @@ int read_sigio_fd(int fd) int n; char c; - n = read(fd, &c, sizeof(c)); + n = os_read_file(fd, &c, sizeof(c)); if(n != sizeof(c)){ - printk("read_sigio_fd - read failed, errno = %d\n", errno); - return(-errno); + if(n < 0) { + printk("read_sigio_fd - read failed, err = %d\n", -n); + return(n); + } + else { + printk("read_sigio_fd - short read, bytes = %d\n", n); + return(-EIO); + } } return(n); } static void sigio_cleanup(void) { - if(write_sigio_pid != -1) + if (write_sigio_pid != -1) { os_kill_process(write_sigio_pid, 1); + write_sigio_pid = -1; + } } __uml_exitcall(sigio_cleanup); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */