X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fum%2Fkernel%2Fsigio_user.c;h=f7b18e157d3509d9b4302b1dc8dfd39c02756630;hb=134734d875a0a48d994ef20b9905209b4b8b6f75;hp=82d19b451d5eaedea9420cfc67ac35f0f8efcc70;hpb=ec9397bab20a628530ce3051167d3d0fcc2c1af7;p=linux-2.6.git diff --git a/arch/um/kernel/sigio_user.c b/arch/um/kernel/sigio_user.c index 82d19b451..f7b18e157 100644 --- a/arch/um/kernel/sigio_user.c +++ b/arch/um/kernel/sigio_user.c @@ -18,7 +18,6 @@ #include "kern_util.h" #include "user_util.h" #include "sigio.h" -#include "helper.h" #include "os.h" /* Changed during early boot */ @@ -108,12 +107,14 @@ static void tty_output(int master, int slave) panic("check_sigio : write failed, errno = %d\n", errno); while(((n = os_read_file(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(n == -EAGAIN) printk("No, enabling workaround\n"); - else panic("check_sigio : read failed, err = %d\n", n); } static void tty_close(int master, int slave) @@ -180,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); @@ -214,6 +216,8 @@ static int write_sigio_thread(void *unused) "err = %d\n", -n); } } + + return 0; } static int need_poll(int n) @@ -222,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"); @@ -235,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; @@ -257,7 +263,7 @@ static void update_thread(void) 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; @@ -265,7 +271,7 @@ static void update_thread(void) os_close_file(sigio_private[1]); os_close_file(write_sigio_fds[0]); os_close_file(write_sigio_fds[1]); - sigio_unlock(); + /* Critical section end */ set_signals(flags); } @@ -331,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(); + + if (l_write_sigio_pid != -1) + return; - err = os_pipe(write_sigio_fds, 1, 1); + err = os_pipe(l_write_sigio_fds, 1, 1); if(err < 0){ printk("write_sigio_workaround - os_pipe 1 failed, " "err = %d\n", -err); - goto out; + return; } - err = os_pipe(sigio_private, 1, 1); + err = os_pipe(l_sigio_private, 1, 1); if(err < 0){ - printk("write_sigio_workaround - os_pipe 2 failed, " + 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: - os_close_file(sigio_private[0]); - os_close_file(sigio_private[1]); + os_close_file(l_sigio_private[0]); + os_close_file(l_sigio_private[1]); out_close1: - os_close_file(write_sigio_fds[0]); - os_close_file(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) @@ -418,19 +457,10 @@ int read_sigio_fd(int fd) 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: - */