18e367065eea04a6fde5cb8f3854164af99c45693Jeff Dike/* 25d33e4d7fd9a52d2673e5c730eab81856e100a74Jeff Dike * Copyright (C) 2002 - 2008 Jeff Dike (jdike@{addtoit,linux.intel}.com) 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Licensed under the GPL 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <unistd.h> 7fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike#include <errno.h> 8fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike#include <fcntl.h> 9fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike#include <poll.h> 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <pty.h> 11fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike#include <sched.h> 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <signal.h> 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <string.h> 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "kern_util.h" 15fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike#include "init.h" 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "os.h" 17fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike#include "sigio.h" 18c13e569073b89eb75216a2551e89ae93ad1f9951Paolo 'Blaisorblade' Giarrusso#include "um_malloc.h" 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike/* 21fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike * Protected by sigio_lock(), also used by sigio_cleanup, which is an 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * exitcall. 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int write_sigio_pid = -1; 25c43990162fc7f9d2f15a12797fdc6f9c0905f704Jeff Dikestatic unsigned long write_sigio_stack; 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike/* 28fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike * These arrays are initialized before the sigio thread is started, and 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the descriptors closed after it is killed. So, it can't see them change. 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * On the UML side, they are changed under the sigio_lock. 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 325f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike#define SIGIO_FDS_INIT {-1, -1} 335f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike 345f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dikestatic int write_sigio_fds[2] = SIGIO_FDS_INIT; 355f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dikestatic int sigio_private[2] = SIGIO_FDS_INIT; 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct pollfds { 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pollfd *poll; 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int size; 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int used; 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike/* 44fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike * Protected by sigio_lock(). Used by the sigio thread, but the UML thread 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * synchronizes with it. 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4719bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dikestatic struct pollfds current_poll; 4819bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dikestatic struct pollfds next_poll; 4919bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dikestatic struct pollfds all_sigio_fds; 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int write_sigio_thread(void *unused) 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pollfds *fds, tmp; 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pollfd *p; 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, n, respond_fd; 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char c; 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 58fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike signal(SIGWINCH, SIG_IGN); 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fds = ¤t_poll; 60fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike while (1) { 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds n = poll(fds->poll, fds->used, -1); 62fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike if (n < 0) { 63fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike if (errno == EINTR) 64fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike continue; 65fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike printk(UM_KERN_ERR "write_sigio_thread : poll returned " 66fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike "%d, errno = %d\n", n, errno); 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 68fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike for (i = 0; i < fds->used; i++) { 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds p = &fds->poll[i]; 70fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike if (p->revents == 0) 71fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike continue; 72fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike if (p->fd == sigio_private[1]) { 73a61f334fd2864b9b040f7e882726426ed7e8a317Jeff Dike CATCH_EINTR(n = read(sigio_private[1], &c, 74a61f334fd2864b9b040f7e882726426ed7e8a317Jeff Dike sizeof(c))); 75fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike if (n != sizeof(c)) 76fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike printk(UM_KERN_ERR 77fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike "write_sigio_thread : " 7819bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike "read on socket failed, " 79a61f334fd2864b9b040f7e882726426ed7e8a317Jeff Dike "err = %d\n", errno); 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp = current_poll; 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds current_poll = next_poll; 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds next_poll = tmp; 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds respond_fd = sigio_private[1]; 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds respond_fd = write_sigio_fds[1]; 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fds->used--; 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memmove(&fds->poll[i], &fds->poll[i + 1], 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (fds->used - i) * sizeof(*fds->poll)); 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 92a61f334fd2864b9b040f7e882726426ed7e8a317Jeff Dike CATCH_EINTR(n = write(respond_fd, &c, sizeof(c))); 93fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike if (n != sizeof(c)) 94fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike printk(UM_KERN_ERR "write_sigio_thread : " 95fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike "write on socket failed, err = %d\n", 96fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike errno); 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 991b57e9c27882a908f180d4daf72ee12c6f137178Jeff Dike 1001b57e9c27882a908f180d4daf72ee12c6f137178Jeff Dike return 0; 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10319bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dikestatic int need_poll(struct pollfds *polls, int n) 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 105838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike struct pollfd *new; 106838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike 107fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike if (n <= polls->size) 10819bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike return 0; 109838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike 11043f5b3085fdd27c4edf535d938b2cb0ccead4f75Jeff Dike new = uml_kmalloc(n * sizeof(struct pollfd), UM_GFP_ATOMIC); 111fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike if (new == NULL) { 112fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike printk(UM_KERN_ERR "need_poll : failed to allocate new " 113fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike "pollfds\n"); 11419bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike return -ENOMEM; 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 116838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike 117838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike memcpy(new, polls->poll, polls->used * sizeof(struct pollfd)); 118838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike kfree(polls->poll); 119838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike 120838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike polls->poll = new; 12119bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike polls->size = n; 12219bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike return 0; 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 125fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike/* 126fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike * Must be called with sigio_lock held, because it's needed by the marked 12719bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike * critical section. 12819bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike */ 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void update_thread(void) 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int n; 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char c; 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds flags = set_signals(0); 136fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike CATCH_EINTR(n = write(sigio_private[0], &c, sizeof(c))); 137fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike if (n != sizeof(c)) { 138fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike printk(UM_KERN_ERR "update_thread : write failed, err = %d\n", 139fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike errno); 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto fail; 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 143a61f334fd2864b9b040f7e882726426ed7e8a317Jeff Dike CATCH_EINTR(n = read(sigio_private[0], &c, sizeof(c))); 144fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike if (n != sizeof(c)) { 145fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike printk(UM_KERN_ERR "update_thread : read failed, err = %d\n", 146fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike errno); 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto fail; 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_signals(flags); 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fail: 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Critical section start */ 154c43990162fc7f9d2f15a12797fdc6f9c0905f704Jeff Dike if (write_sigio_pid != -1) { 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds os_kill_process(write_sigio_pid, 1); 156c43990162fc7f9d2f15a12797fdc6f9c0905f704Jeff Dike free_stack(write_sigio_stack, 0); 157c43990162fc7f9d2f15a12797fdc6f9c0905f704Jeff Dike } 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_sigio_pid = -1; 1598e367065eea04a6fde5cb8f3854164af99c45693Jeff Dike close(sigio_private[0]); 1608e367065eea04a6fde5cb8f3854164af99c45693Jeff Dike close(sigio_private[1]); 1618e367065eea04a6fde5cb8f3854164af99c45693Jeff Dike close(write_sigio_fds[0]); 1628e367065eea04a6fde5cb8f3854164af99c45693Jeff Dike close(write_sigio_fds[1]); 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Critical section end */ 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_signals(flags); 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16719bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dikeint add_sigio_fd(int fd) 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16919bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike struct pollfd *p; 17019bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike int err = 0, i, n; 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sigio_lock(); 173fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike for (i = 0; i < all_sigio_fds.used; i++) { 174fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike if (all_sigio_fds.poll[i].fd == fd) 17519bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike break; 17619bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike } 177fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike if (i == all_sigio_fds.used) 17819bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike goto out; 17919bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike 18019bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike p = &all_sigio_fds.poll[i]; 18119bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike 182fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike for (i = 0; i < current_poll.used; i++) { 183fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike if (current_poll.poll[i].fd == fd) 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 187838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike n = current_poll.used; 188838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike err = need_poll(&next_poll, n + 1); 189fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike if (err) 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 192838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike memcpy(next_poll.poll, current_poll.poll, 193838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike current_poll.used * sizeof(struct pollfd)); 194838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike next_poll.poll[n] = *p; 195838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike next_poll.used = n + 1; 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds update_thread(); 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out: 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sigio_unlock(); 19919bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike return err; 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint ignore_sigio_fd(int fd) 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pollfd *p; 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err = 0, i, n = 0; 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 207fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike /* 208fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike * This is called from exitcalls elsewhere in UML - if 20961232f2fe44f7ac12d7512d099a8f10923eff7eaJeff Dike * sigio_cleanup has already run, then update_thread will hang 21061232f2fe44f7ac12d7512d099a8f10923eff7eaJeff Dike * or fail because the thread is no longer running. 21161232f2fe44f7ac12d7512d099a8f10923eff7eaJeff Dike */ 212fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike if (write_sigio_pid == -1) 21361232f2fe44f7ac12d7512d099a8f10923eff7eaJeff Dike return -EIO; 21461232f2fe44f7ac12d7512d099a8f10923eff7eaJeff Dike 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sigio_lock(); 216fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike for (i = 0; i < current_poll.used; i++) { 217fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike if (current_poll.poll[i].fd == fd) 218fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike break; 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 220fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike if (i == current_poll.used) 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 222f206aabb035318ac4bafbf0b87798335de3634dfJeff Dike 22319bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike err = need_poll(&next_poll, current_poll.used - 1); 224fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike if (err) 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 227fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike for (i = 0; i < current_poll.used; i++) { 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds p = ¤t_poll.poll[i]; 229fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike if (p->fd != fd) 23019bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike next_poll.poll[n++] = *p; 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 232838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike next_poll.used = current_poll.used - 1; 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds update_thread(); 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out: 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sigio_unlock(); 23761232f2fe44f7ac12d7512d099a8f10923eff7eaJeff Dike return err; 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 240f206aabb035318ac4bafbf0b87798335de3634dfJeff Dikestatic struct pollfd *setup_initial_poll(int fd) 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pollfd *p; 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24443f5b3085fdd27c4edf535d938b2cb0ccead4f75Jeff Dike p = uml_kmalloc(sizeof(struct pollfd), UM_GFP_KERNEL); 245b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso if (p == NULL) { 246fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike printk(UM_KERN_ERR "setup_initial_poll : failed to allocate " 247fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike "poll\n"); 248b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso return NULL; 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 25019bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike *p = ((struct pollfd) { .fd = fd, 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .events = POLLIN, 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .revents = 0 }); 253b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso return p; 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2568e64d96aeb495709c13307e2d79f3ee37e96aa4eJeff Dikestatic void write_sigio_workaround(void) 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 258b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso struct pollfd *p; 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 260b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso int l_write_sigio_fds[2]; 261b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso int l_sigio_private[2]; 262b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso int l_write_sigio_pid; 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 264b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso /* We call this *tons* of times - and most ones we must just fail. */ 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sigio_lock(); 266b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso l_write_sigio_pid = write_sigio_pid; 267b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso sigio_unlock(); 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 269b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso if (l_write_sigio_pid != -1) 270b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso return; 271b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso 272b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso err = os_pipe(l_write_sigio_fds, 1, 1); 273fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike if (err < 0) { 274fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike printk(UM_KERN_ERR "write_sigio_workaround - os_pipe 1 failed, " 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "err = %d\n", -err); 276b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso return; 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 278b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso err = os_pipe(l_sigio_private, 1, 1); 279fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike if (err < 0) { 280fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike printk(UM_KERN_ERR "write_sigio_workaround - os_pipe 2 failed, " 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "err = %d\n", -err); 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_close1; 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 284b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso 285b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso p = setup_initial_poll(l_sigio_private[1]); 286fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike if (!p) 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_close2; 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 289b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso sigio_lock(); 290b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso 291fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike /* 292fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike * Did we race? Don't try to optimize this, please, it's not so likely 293fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike * to happen, and no more than once at the boot. 294fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike */ 295fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike if (write_sigio_pid != -1) 2965f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike goto out_free; 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2985f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike current_poll = ((struct pollfds) { .poll = p, 2995f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike .used = 1, 3005f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike .size = 1 }); 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 302b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso if (write_sigio_irq(l_write_sigio_fds[0])) 3035f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike goto out_clear_poll; 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 305b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso memcpy(write_sigio_fds, l_write_sigio_fds, sizeof(l_write_sigio_fds)); 306b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso memcpy(sigio_private, l_sigio_private, sizeof(l_sigio_private)); 307b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso 3085f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike write_sigio_pid = run_helper_thread(write_sigio_thread, NULL, 309c43990162fc7f9d2f15a12797fdc6f9c0905f704Jeff Dike CLONE_FILES | CLONE_VM, 310c43990162fc7f9d2f15a12797fdc6f9c0905f704Jeff Dike &write_sigio_stack); 311b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso 3125f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike if (write_sigio_pid < 0) 3135f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike goto out_clear; 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 315b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso sigio_unlock(); 3165f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike return; 317b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso 3185f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dikeout_clear: 319b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso write_sigio_pid = -1; 3205f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike write_sigio_fds[0] = -1; 3215f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike write_sigio_fds[1] = -1; 3225f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike sigio_private[0] = -1; 3235f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike sigio_private[1] = -1; 3245f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dikeout_clear_poll: 3255f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike current_poll = ((struct pollfds) { .poll = NULL, 3265f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike .size = 0, 3275f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike .used = 0 }); 3285f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dikeout_free: 3295f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike sigio_unlock(); 330e6fb54abb8a36703f54b7e27a756a3df6667c37bPaolo 'Blaisorblade' Giarrusso kfree(p); 3315f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dikeout_close2: 3328e367065eea04a6fde5cb8f3854164af99c45693Jeff Dike close(l_sigio_private[0]); 3338e367065eea04a6fde5cb8f3854164af99c45693Jeff Dike close(l_sigio_private[1]); 3345f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dikeout_close1: 3358e367065eea04a6fde5cb8f3854164af99c45693Jeff Dike close(l_write_sigio_fds[0]); 3368e367065eea04a6fde5cb8f3854164af99c45693Jeff Dike close(l_write_sigio_fds[1]); 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3395d33e4d7fd9a52d2673e5c730eab81856e100a74Jeff Dikevoid sigio_broken(int fd, int read) 3408e64d96aeb495709c13307e2d79f3ee37e96aa4eJeff Dike{ 34119bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike int err; 34219bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike 3438e64d96aeb495709c13307e2d79f3ee37e96aa4eJeff Dike write_sigio_workaround(); 34419bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike 34519bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike sigio_lock(); 34619bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike err = need_poll(&all_sigio_fds, all_sigio_fds.used + 1); 347fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike if (err) { 348fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike printk(UM_KERN_ERR "maybe_sigio_broken - failed to add pollfd " 349fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike "for descriptor %d\n", fd); 35019bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike goto out; 35104a51e66adcdc0de6ffaa488934ce3ffb3818ecfJeff Dike } 352838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike 35319bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike all_sigio_fds.poll[all_sigio_fds.used++] = 35419bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike ((struct pollfd) { .fd = fd, 35519bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike .events = read ? POLLIN : POLLOUT, 35619bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike .revents = 0 }); 35719bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dikeout: 35819bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike sigio_unlock(); 3598e64d96aeb495709c13307e2d79f3ee37e96aa4eJeff Dike} 3608e64d96aeb495709c13307e2d79f3ee37e96aa4eJeff Dike 3615d33e4d7fd9a52d2673e5c730eab81856e100a74Jeff Dike/* Changed during early boot */ 3625d33e4d7fd9a52d2673e5c730eab81856e100a74Jeff Dikestatic int pty_output_sigio; 3635d33e4d7fd9a52d2673e5c730eab81856e100a74Jeff Dikestatic int pty_close_sigio; 3645d33e4d7fd9a52d2673e5c730eab81856e100a74Jeff Dike 3655d33e4d7fd9a52d2673e5c730eab81856e100a74Jeff Dikevoid maybe_sigio_broken(int fd, int read) 3665d33e4d7fd9a52d2673e5c730eab81856e100a74Jeff Dike{ 3675d33e4d7fd9a52d2673e5c730eab81856e100a74Jeff Dike if (!isatty(fd)) 3685d33e4d7fd9a52d2673e5c730eab81856e100a74Jeff Dike return; 3695d33e4d7fd9a52d2673e5c730eab81856e100a74Jeff Dike 3705d33e4d7fd9a52d2673e5c730eab81856e100a74Jeff Dike if ((read || pty_output_sigio) && (!read || pty_close_sigio)) 3715d33e4d7fd9a52d2673e5c730eab81856e100a74Jeff Dike return; 3725d33e4d7fd9a52d2673e5c730eab81856e100a74Jeff Dike 3735d33e4d7fd9a52d2673e5c730eab81856e100a74Jeff Dike sigio_broken(fd, read); 3745d33e4d7fd9a52d2673e5c730eab81856e100a74Jeff Dike} 3755d33e4d7fd9a52d2673e5c730eab81856e100a74Jeff Dike 37629ac1c2142346e1e0e072f41df31688fc42ff540Jeff Dikestatic void sigio_cleanup(void) 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 378c43990162fc7f9d2f15a12797fdc6f9c0905f704Jeff Dike if (write_sigio_pid == -1) 379c43990162fc7f9d2f15a12797fdc6f9c0905f704Jeff Dike return; 380c43990162fc7f9d2f15a12797fdc6f9c0905f704Jeff Dike 381c43990162fc7f9d2f15a12797fdc6f9c0905f704Jeff Dike os_kill_process(write_sigio_pid, 1); 382c43990162fc7f9d2f15a12797fdc6f9c0905f704Jeff Dike free_stack(write_sigio_stack, 0); 383c43990162fc7f9d2f15a12797fdc6f9c0905f704Jeff Dike write_sigio_pid = -1; 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 38529ac1c2142346e1e0e072f41df31688fc42ff540Jeff Dike 38629ac1c2142346e1e0e072f41df31688fc42ff540Jeff Dike__uml_exitcall(sigio_cleanup); 387c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike 388c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike/* Used as a flag during SIGIO testing early in boot */ 3895d33e4d7fd9a52d2673e5c730eab81856e100a74Jeff Dikestatic int got_sigio; 390c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike 391c65badbdf5dc117e45873e760f807063ad59a854Jeff Dikestatic void __init handler(int sig) 392c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike{ 393c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike got_sigio = 1; 394c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike} 395c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike 396c65badbdf5dc117e45873e760f807063ad59a854Jeff Dikestruct openpty_arg { 397c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike int master; 398c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike int slave; 399c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike int err; 400c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike}; 401c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike 402c65badbdf5dc117e45873e760f807063ad59a854Jeff Dikestatic void openpty_cb(void *arg) 403c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike{ 404c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike struct openpty_arg *info = arg; 405c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike 406c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike info->err = 0; 407fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike if (openpty(&info->master, &info->slave, NULL, NULL, NULL)) 408c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike info->err = -errno; 409c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike} 410c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike 411c65badbdf5dc117e45873e760f807063ad59a854Jeff Dikestatic int async_pty(int master, int slave) 412c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike{ 413c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike int flags; 414c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike 415c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike flags = fcntl(master, F_GETFL); 416fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike if (flags < 0) 417c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike return -errno; 418c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike 419fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike if ((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) || 420fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike (fcntl(master, F_SETOWN, os_getpid()) < 0)) 421c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike return -errno; 422c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike 423fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike if ((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0)) 424c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike return -errno; 425c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike 426c0a9290ecf0dbb89958cb3a3f78964015a7de402WANG Cong return 0; 427c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike} 428c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike 429c65badbdf5dc117e45873e760f807063ad59a854Jeff Dikestatic void __init check_one_sigio(void (*proc)(int, int)) 430c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike{ 431c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike struct sigaction old, new; 432c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike struct openpty_arg pty = { .master = -1, .slave = -1 }; 433c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike int master, slave, err; 434c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike 435c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike initial_thread_cb(openpty_cb, &pty); 436fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike if (pty.err) { 437fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike printk(UM_KERN_ERR "check_one_sigio failed, errno = %d\n", 438fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike -pty.err); 439c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike return; 440c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike } 441c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike 442c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike master = pty.master; 443c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike slave = pty.slave; 444c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike 445fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike if ((master == -1) || (slave == -1)) { 446fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike printk(UM_KERN_ERR "check_one_sigio failed to allocate a " 447fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike "pty\n"); 448c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike return; 449c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike } 450c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike 451c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike /* Not now, but complain so we now where we failed. */ 452c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike err = raw(master); 453fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike if (err < 0) { 454fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike printk(UM_KERN_ERR "check_one_sigio : raw failed, errno = %d\n", 455fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike -err); 456fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike return; 457fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike } 458c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike 459c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike err = async_pty(master, slave); 460fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike if (err < 0) { 461fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike printk(UM_KERN_ERR "check_one_sigio : sigio_async failed, " 462fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike "err = %d\n", -err); 463fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike return; 464fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike } 465fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike 466fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike if (sigaction(SIGIO, NULL, &old) < 0) { 467fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike printk(UM_KERN_ERR "check_one_sigio : sigaction 1 failed, " 468fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike "errno = %d\n", errno); 469fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike return; 470fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike } 471c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike 472c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike new = old; 473c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike new.sa_handler = handler; 474fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike if (sigaction(SIGIO, &new, NULL) < 0) { 475fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike printk(UM_KERN_ERR "check_one_sigio : sigaction 2 failed, " 476fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike "errno = %d\n", errno); 477fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike return; 478fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike } 479c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike 480c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike got_sigio = 0; 481c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike (*proc)(master, slave); 482c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike 483c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike close(master); 484c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike close(slave); 485c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike 486fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike if (sigaction(SIGIO, &old, NULL) < 0) 487fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike printk(UM_KERN_ERR "check_one_sigio : sigaction 3 failed, " 488fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike "errno = %d\n", errno); 489c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike} 490c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike 491c65badbdf5dc117e45873e760f807063ad59a854Jeff Dikestatic void tty_output(int master, int slave) 492c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike{ 493c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike int n; 494c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike char buf[512]; 495c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike 496fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike printk(UM_KERN_INFO "Checking that host ptys support output SIGIO..."); 497c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike 498c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike memset(buf, 0, sizeof(buf)); 499c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike 500fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike while (write(master, buf, sizeof(buf)) > 0) ; 501fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike if (errno != EAGAIN) 502fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike printk(UM_KERN_ERR "tty_output : write failed, errno = %d\n", 503fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike errno); 5045d33e4d7fd9a52d2673e5c730eab81856e100a74Jeff Dike while (((n = read(slave, buf, sizeof(buf))) > 0) && 5055d33e4d7fd9a52d2673e5c730eab81856e100a74Jeff Dike !({ barrier(); got_sigio; })) 506fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike ; 507c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike 508fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike if (got_sigio) { 509fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike printk(UM_KERN_CONT "Yes\n"); 510c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike pty_output_sigio = 1; 511fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike } else if (n == -EAGAIN) 512fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike printk(UM_KERN_CONT "No, enabling workaround\n"); 513fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike else 514fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike printk(UM_KERN_CONT "tty_output : read failed, err = %d\n", n); 515c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike} 516c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike 517c65badbdf5dc117e45873e760f807063ad59a854Jeff Dikestatic void tty_close(int master, int slave) 518c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike{ 519fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike printk(UM_KERN_INFO "Checking that host ptys support SIGIO on " 520fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike "close..."); 521c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike 522c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike close(slave); 523fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike if (got_sigio) { 524fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike printk(UM_KERN_CONT "Yes\n"); 525c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike pty_close_sigio = 1; 526fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike } else 527fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike printk(UM_KERN_CONT "No, enabling workaround\n"); 528c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike} 529c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike 53099764fa4ceeecba8b9e0a8a5565b418a2e94f83bWANG Congstatic void __init check_sigio(void) 531c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike{ 532fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike if ((access("/dev/ptmx", R_OK) < 0) && 533fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike (access("/dev/ptyp0", R_OK) < 0)) { 534fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike printk(UM_KERN_WARNING "No pseudo-terminals available - " 535fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike "skipping pty SIGIO check\n"); 536c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike return; 537c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike } 538c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike check_one_sigio(tty_output); 539c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike check_one_sigio(tty_close); 540c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike} 541c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike 542c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike/* Here because it only does the SIGIO testing for now */ 543c65badbdf5dc117e45873e760f807063ad59a854Jeff Dikevoid __init os_check_bugs(void) 544c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike{ 545c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike check_sigio(); 546c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike} 547