1f206aabbSJeff Dike /* 25d33e4d7SJeff Dike * Copyright (C) 2002 - 2008 Jeff Dike (jdike@{addtoit,linux.intel}.com) 3f206aabbSJeff Dike * Licensed under the GPL 4f206aabbSJeff Dike */ 5f206aabbSJeff Dike 6f206aabbSJeff Dike #include <unistd.h> 7f206aabbSJeff Dike #include <errno.h> 8fee64d3cSJeff Dike #include <fcntl.h> 9fee64d3cSJeff Dike #include <poll.h> 10fee64d3cSJeff Dike #include <pty.h> 11f206aabbSJeff Dike #include <sched.h> 12fee64d3cSJeff Dike #include <signal.h> 13fee64d3cSJeff Dike #include <string.h> 14fee64d3cSJeff Dike #include "kern_constants.h" 15f206aabbSJeff Dike #include "kern_util.h" 16fee64d3cSJeff Dike #include "init.h" 17f206aabbSJeff Dike #include "os.h" 185d33e4d7SJeff Dike #include "process.h" 19fee64d3cSJeff Dike #include "sigio.h" 20c13e5690SPaolo 'Blaisorblade' Giarrusso #include "um_malloc.h" 21fee64d3cSJeff Dike #include "user.h" 22f206aabbSJeff Dike 23fee64d3cSJeff Dike /* 24fee64d3cSJeff Dike * Protected by sigio_lock(), also used by sigio_cleanup, which is an 25f206aabbSJeff Dike * exitcall. 26f206aabbSJeff Dike */ 27f206aabbSJeff Dike static int write_sigio_pid = -1; 28c4399016SJeff Dike static unsigned long write_sigio_stack; 29f206aabbSJeff Dike 30fee64d3cSJeff Dike /* 31fee64d3cSJeff Dike * These arrays are initialized before the sigio thread is started, and 32f206aabbSJeff Dike * the descriptors closed after it is killed. So, it can't see them change. 33f206aabbSJeff Dike * On the UML side, they are changed under the sigio_lock. 34f206aabbSJeff Dike */ 355f4e8fd0SJeff Dike #define SIGIO_FDS_INIT {-1, -1} 365f4e8fd0SJeff Dike 375f4e8fd0SJeff Dike static int write_sigio_fds[2] = SIGIO_FDS_INIT; 385f4e8fd0SJeff Dike static int sigio_private[2] = SIGIO_FDS_INIT; 39f206aabbSJeff Dike 40f206aabbSJeff Dike struct pollfds { 41f206aabbSJeff Dike struct pollfd *poll; 42f206aabbSJeff Dike int size; 43f206aabbSJeff Dike int used; 44f206aabbSJeff Dike }; 45f206aabbSJeff Dike 46fee64d3cSJeff Dike /* 47fee64d3cSJeff Dike * Protected by sigio_lock(). Used by the sigio thread, but the UML thread 48f206aabbSJeff Dike * synchronizes with it. 49f206aabbSJeff Dike */ 5019bdf040SJeff Dike static struct pollfds current_poll; 5119bdf040SJeff Dike static struct pollfds next_poll; 5219bdf040SJeff Dike static struct pollfds all_sigio_fds; 53f206aabbSJeff Dike 54f206aabbSJeff Dike static int write_sigio_thread(void *unused) 55f206aabbSJeff Dike { 56f206aabbSJeff Dike struct pollfds *fds, tmp; 57f206aabbSJeff Dike struct pollfd *p; 58f206aabbSJeff Dike int i, n, respond_fd; 59f206aabbSJeff Dike char c; 60f206aabbSJeff Dike 61f206aabbSJeff Dike signal(SIGWINCH, SIG_IGN); 62f206aabbSJeff Dike fds = ¤t_poll; 63f206aabbSJeff Dike while (1) { 64f206aabbSJeff Dike n = poll(fds->poll, fds->used, -1); 65f206aabbSJeff Dike if (n < 0) { 66fee64d3cSJeff Dike if (errno == EINTR) 67fee64d3cSJeff Dike continue; 68fee64d3cSJeff Dike printk(UM_KERN_ERR "write_sigio_thread : poll returned " 69fee64d3cSJeff Dike "%d, errno = %d\n", n, errno); 70f206aabbSJeff Dike } 71f206aabbSJeff Dike for (i = 0; i < fds->used; i++) { 72f206aabbSJeff Dike p = &fds->poll[i]; 73fee64d3cSJeff Dike if (p->revents == 0) 74fee64d3cSJeff Dike continue; 75f206aabbSJeff Dike if (p->fd == sigio_private[1]) { 76a61f334fSJeff Dike CATCH_EINTR(n = read(sigio_private[1], &c, 77a61f334fSJeff Dike sizeof(c))); 78f206aabbSJeff Dike if (n != sizeof(c)) 79fee64d3cSJeff Dike printk(UM_KERN_ERR 80fee64d3cSJeff Dike "write_sigio_thread : " 8119bdf040SJeff Dike "read on socket failed, " 82a61f334fSJeff Dike "err = %d\n", errno); 83f206aabbSJeff Dike tmp = current_poll; 84f206aabbSJeff Dike current_poll = next_poll; 85f206aabbSJeff Dike next_poll = tmp; 86f206aabbSJeff Dike respond_fd = sigio_private[1]; 87f206aabbSJeff Dike } 88f206aabbSJeff Dike else { 89f206aabbSJeff Dike respond_fd = write_sigio_fds[1]; 90f206aabbSJeff Dike fds->used--; 91f206aabbSJeff Dike memmove(&fds->poll[i], &fds->poll[i + 1], 92f206aabbSJeff Dike (fds->used - i) * sizeof(*fds->poll)); 93f206aabbSJeff Dike } 94f206aabbSJeff Dike 95a61f334fSJeff Dike CATCH_EINTR(n = write(respond_fd, &c, sizeof(c))); 96f206aabbSJeff Dike if (n != sizeof(c)) 97fee64d3cSJeff Dike printk(UM_KERN_ERR "write_sigio_thread : " 98fee64d3cSJeff Dike "write on socket failed, err = %d\n", 99fee64d3cSJeff Dike errno); 100f206aabbSJeff Dike } 101f206aabbSJeff Dike } 102f206aabbSJeff Dike 103f206aabbSJeff Dike return 0; 104f206aabbSJeff Dike } 105f206aabbSJeff Dike 10619bdf040SJeff Dike static int need_poll(struct pollfds *polls, int n) 107f206aabbSJeff Dike { 108838e56a1SJeff Dike struct pollfd *new; 109838e56a1SJeff Dike 110838e56a1SJeff Dike if (n <= polls->size) 11119bdf040SJeff Dike return 0; 112838e56a1SJeff Dike 11343f5b308SJeff Dike new = uml_kmalloc(n * sizeof(struct pollfd), UM_GFP_ATOMIC); 114838e56a1SJeff Dike if (new == NULL) { 115fee64d3cSJeff Dike printk(UM_KERN_ERR "need_poll : failed to allocate new " 116fee64d3cSJeff Dike "pollfds\n"); 11719bdf040SJeff Dike return -ENOMEM; 118f206aabbSJeff Dike } 119838e56a1SJeff Dike 120838e56a1SJeff Dike memcpy(new, polls->poll, polls->used * sizeof(struct pollfd)); 121838e56a1SJeff Dike kfree(polls->poll); 122838e56a1SJeff Dike 123838e56a1SJeff Dike polls->poll = new; 12419bdf040SJeff Dike polls->size = n; 12519bdf040SJeff Dike return 0; 126f206aabbSJeff Dike } 127f206aabbSJeff Dike 128fee64d3cSJeff Dike /* 129fee64d3cSJeff Dike * Must be called with sigio_lock held, because it's needed by the marked 13019bdf040SJeff Dike * critical section. 13119bdf040SJeff Dike */ 132f206aabbSJeff Dike static void update_thread(void) 133f206aabbSJeff Dike { 134f206aabbSJeff Dike unsigned long flags; 135f206aabbSJeff Dike int n; 136f206aabbSJeff Dike char c; 137f206aabbSJeff Dike 138f206aabbSJeff Dike flags = set_signals(0); 139fee64d3cSJeff Dike CATCH_EINTR(n = write(sigio_private[0], &c, sizeof(c))); 140f206aabbSJeff Dike if (n != sizeof(c)) { 141fee64d3cSJeff Dike printk(UM_KERN_ERR "update_thread : write failed, err = %d\n", 142fee64d3cSJeff Dike errno); 143f206aabbSJeff Dike goto fail; 144f206aabbSJeff Dike } 145f206aabbSJeff Dike 146a61f334fSJeff Dike CATCH_EINTR(n = read(sigio_private[0], &c, sizeof(c))); 147f206aabbSJeff Dike if (n != sizeof(c)) { 148fee64d3cSJeff Dike printk(UM_KERN_ERR "update_thread : read failed, err = %d\n", 149fee64d3cSJeff Dike errno); 150f206aabbSJeff Dike goto fail; 151f206aabbSJeff Dike } 152f206aabbSJeff Dike 153f206aabbSJeff Dike set_signals(flags); 154f206aabbSJeff Dike return; 155f206aabbSJeff Dike fail: 156f206aabbSJeff Dike /* Critical section start */ 157c4399016SJeff Dike if (write_sigio_pid != -1) { 158f206aabbSJeff Dike os_kill_process(write_sigio_pid, 1); 159c4399016SJeff Dike free_stack(write_sigio_stack, 0); 160c4399016SJeff Dike } 161f206aabbSJeff Dike write_sigio_pid = -1; 162f206aabbSJeff Dike close(sigio_private[0]); 163f206aabbSJeff Dike close(sigio_private[1]); 164f206aabbSJeff Dike close(write_sigio_fds[0]); 165f206aabbSJeff Dike close(write_sigio_fds[1]); 166f206aabbSJeff Dike /* Critical section end */ 167f206aabbSJeff Dike set_signals(flags); 168f206aabbSJeff Dike } 169f206aabbSJeff Dike 17019bdf040SJeff Dike int add_sigio_fd(int fd) 171f206aabbSJeff Dike { 17219bdf040SJeff Dike struct pollfd *p; 17319bdf040SJeff Dike int err = 0, i, n; 174f206aabbSJeff Dike 175f206aabbSJeff Dike sigio_lock(); 17619bdf040SJeff Dike for (i = 0; i < all_sigio_fds.used; i++) { 17719bdf040SJeff Dike if (all_sigio_fds.poll[i].fd == fd) 17819bdf040SJeff Dike break; 17919bdf040SJeff Dike } 18019bdf040SJeff Dike if (i == all_sigio_fds.used) 18119bdf040SJeff Dike goto out; 18219bdf040SJeff Dike 18319bdf040SJeff Dike p = &all_sigio_fds.poll[i]; 18419bdf040SJeff Dike 185f206aabbSJeff Dike for (i = 0; i < current_poll.used; i++) { 186f206aabbSJeff Dike if (current_poll.poll[i].fd == fd) 187f206aabbSJeff Dike goto out; 188f206aabbSJeff Dike } 189f206aabbSJeff Dike 190838e56a1SJeff Dike n = current_poll.used; 191838e56a1SJeff Dike err = need_poll(&next_poll, n + 1); 192f206aabbSJeff Dike if (err) 193f206aabbSJeff Dike goto out; 194f206aabbSJeff Dike 195838e56a1SJeff Dike memcpy(next_poll.poll, current_poll.poll, 196838e56a1SJeff Dike current_poll.used * sizeof(struct pollfd)); 197838e56a1SJeff Dike next_poll.poll[n] = *p; 198838e56a1SJeff Dike next_poll.used = n + 1; 199f206aabbSJeff Dike update_thread(); 200f206aabbSJeff Dike out: 201f206aabbSJeff Dike sigio_unlock(); 20219bdf040SJeff Dike return err; 203f206aabbSJeff Dike } 204f206aabbSJeff Dike 205f206aabbSJeff Dike int ignore_sigio_fd(int fd) 206f206aabbSJeff Dike { 207f206aabbSJeff Dike struct pollfd *p; 208f206aabbSJeff Dike int err = 0, i, n = 0; 209f206aabbSJeff Dike 210fee64d3cSJeff Dike /* 211fee64d3cSJeff Dike * This is called from exitcalls elsewhere in UML - if 21261232f2fSJeff Dike * sigio_cleanup has already run, then update_thread will hang 21361232f2fSJeff Dike * or fail because the thread is no longer running. 21461232f2fSJeff Dike */ 21561232f2fSJeff Dike if (write_sigio_pid == -1) 21661232f2fSJeff Dike return -EIO; 21761232f2fSJeff Dike 218f206aabbSJeff Dike sigio_lock(); 219f206aabbSJeff Dike for (i = 0; i < current_poll.used; i++) { 220fee64d3cSJeff Dike if (current_poll.poll[i].fd == fd) 221fee64d3cSJeff Dike break; 222f206aabbSJeff Dike } 223f206aabbSJeff Dike if (i == current_poll.used) 224f206aabbSJeff Dike goto out; 225f206aabbSJeff Dike 22619bdf040SJeff Dike err = need_poll(&next_poll, current_poll.used - 1); 227f206aabbSJeff Dike if (err) 228f206aabbSJeff Dike goto out; 229f206aabbSJeff Dike 230f206aabbSJeff Dike for (i = 0; i < current_poll.used; i++) { 231f206aabbSJeff Dike p = ¤t_poll.poll[i]; 23219bdf040SJeff Dike if (p->fd != fd) 23319bdf040SJeff Dike next_poll.poll[n++] = *p; 234f206aabbSJeff Dike } 235838e56a1SJeff Dike next_poll.used = current_poll.used - 1; 236f206aabbSJeff Dike 237f206aabbSJeff Dike update_thread(); 238f206aabbSJeff Dike out: 239f206aabbSJeff Dike sigio_unlock(); 24061232f2fSJeff Dike return err; 241f206aabbSJeff Dike } 242f206aabbSJeff Dike 243f206aabbSJeff Dike static struct pollfd *setup_initial_poll(int fd) 244f206aabbSJeff Dike { 245f206aabbSJeff Dike struct pollfd *p; 246f206aabbSJeff Dike 24743f5b308SJeff Dike p = uml_kmalloc(sizeof(struct pollfd), UM_GFP_KERNEL); 248f206aabbSJeff Dike if (p == NULL) { 249fee64d3cSJeff Dike printk(UM_KERN_ERR "setup_initial_poll : failed to allocate " 250fee64d3cSJeff Dike "poll\n"); 251f206aabbSJeff Dike return NULL; 252f206aabbSJeff Dike } 253f206aabbSJeff Dike *p = ((struct pollfd) { .fd = fd, 254f206aabbSJeff Dike .events = POLLIN, 255f206aabbSJeff Dike .revents = 0 }); 256f206aabbSJeff Dike return p; 257f206aabbSJeff Dike } 258f206aabbSJeff Dike 2598e64d96aSJeff Dike static void write_sigio_workaround(void) 260f206aabbSJeff Dike { 261f206aabbSJeff Dike struct pollfd *p; 262f206aabbSJeff Dike int err; 263f206aabbSJeff Dike int l_write_sigio_fds[2]; 264f206aabbSJeff Dike int l_sigio_private[2]; 265f206aabbSJeff Dike int l_write_sigio_pid; 266f206aabbSJeff Dike 267f206aabbSJeff Dike /* We call this *tons* of times - and most ones we must just fail. */ 268f206aabbSJeff Dike sigio_lock(); 269f206aabbSJeff Dike l_write_sigio_pid = write_sigio_pid; 270f206aabbSJeff Dike sigio_unlock(); 271f206aabbSJeff Dike 272f206aabbSJeff Dike if (l_write_sigio_pid != -1) 273f206aabbSJeff Dike return; 274f206aabbSJeff Dike 275f206aabbSJeff Dike err = os_pipe(l_write_sigio_fds, 1, 1); 276f206aabbSJeff Dike if (err < 0) { 277fee64d3cSJeff Dike printk(UM_KERN_ERR "write_sigio_workaround - os_pipe 1 failed, " 278f206aabbSJeff Dike "err = %d\n", -err); 279f206aabbSJeff Dike return; 280f206aabbSJeff Dike } 281f206aabbSJeff Dike err = os_pipe(l_sigio_private, 1, 1); 282f206aabbSJeff Dike if (err < 0) { 283fee64d3cSJeff Dike printk(UM_KERN_ERR "write_sigio_workaround - os_pipe 2 failed, " 284f206aabbSJeff Dike "err = %d\n", -err); 285f206aabbSJeff Dike goto out_close1; 286f206aabbSJeff Dike } 287f206aabbSJeff Dike 288f206aabbSJeff Dike p = setup_initial_poll(l_sigio_private[1]); 289f206aabbSJeff Dike if (!p) 290f206aabbSJeff Dike goto out_close2; 291f206aabbSJeff Dike 292f206aabbSJeff Dike sigio_lock(); 293f206aabbSJeff Dike 294fee64d3cSJeff Dike /* 295fee64d3cSJeff Dike * Did we race? Don't try to optimize this, please, it's not so likely 296fee64d3cSJeff Dike * to happen, and no more than once at the boot. 297fee64d3cSJeff Dike */ 298f206aabbSJeff Dike if (write_sigio_pid != -1) 2995f4e8fd0SJeff Dike goto out_free; 3005f4e8fd0SJeff Dike 3015f4e8fd0SJeff Dike current_poll = ((struct pollfds) { .poll = p, 3025f4e8fd0SJeff Dike .used = 1, 3035f4e8fd0SJeff Dike .size = 1 }); 3045f4e8fd0SJeff Dike 3055f4e8fd0SJeff Dike if (write_sigio_irq(l_write_sigio_fds[0])) 3065f4e8fd0SJeff Dike goto out_clear_poll; 3075f4e8fd0SJeff Dike 3085f4e8fd0SJeff Dike memcpy(write_sigio_fds, l_write_sigio_fds, sizeof(l_write_sigio_fds)); 3095f4e8fd0SJeff Dike memcpy(sigio_private, l_sigio_private, sizeof(l_sigio_private)); 310f206aabbSJeff Dike 311f206aabbSJeff Dike write_sigio_pid = run_helper_thread(write_sigio_thread, NULL, 312c4399016SJeff Dike CLONE_FILES | CLONE_VM, 313c4399016SJeff Dike &write_sigio_stack); 314f206aabbSJeff Dike 315f206aabbSJeff Dike if (write_sigio_pid < 0) 316f206aabbSJeff Dike goto out_clear; 317f206aabbSJeff Dike 318f206aabbSJeff Dike sigio_unlock(); 319f206aabbSJeff Dike return; 320f206aabbSJeff Dike 321f206aabbSJeff Dike out_clear: 322f206aabbSJeff Dike write_sigio_pid = -1; 3235f4e8fd0SJeff Dike write_sigio_fds[0] = -1; 3245f4e8fd0SJeff Dike write_sigio_fds[1] = -1; 3255f4e8fd0SJeff Dike sigio_private[0] = -1; 3265f4e8fd0SJeff Dike sigio_private[1] = -1; 3275f4e8fd0SJeff Dike out_clear_poll: 3285f4e8fd0SJeff Dike current_poll = ((struct pollfds) { .poll = NULL, 3295f4e8fd0SJeff Dike .size = 0, 3305f4e8fd0SJeff Dike .used = 0 }); 331f206aabbSJeff Dike out_free: 3325f4e8fd0SJeff Dike sigio_unlock(); 333e6fb54abSPaolo 'Blaisorblade' Giarrusso kfree(p); 334f206aabbSJeff Dike out_close2: 335f206aabbSJeff Dike close(l_sigio_private[0]); 336f206aabbSJeff Dike close(l_sigio_private[1]); 337f206aabbSJeff Dike out_close1: 338f206aabbSJeff Dike close(l_write_sigio_fds[0]); 339f206aabbSJeff Dike close(l_write_sigio_fds[1]); 340f206aabbSJeff Dike } 341f206aabbSJeff Dike 3425d33e4d7SJeff Dike void sigio_broken(int fd, int read) 3438e64d96aSJeff Dike { 34419bdf040SJeff Dike int err; 34519bdf040SJeff Dike 3468e64d96aSJeff Dike write_sigio_workaround(); 34719bdf040SJeff Dike 34819bdf040SJeff Dike sigio_lock(); 34919bdf040SJeff Dike err = need_poll(&all_sigio_fds, all_sigio_fds.used + 1); 35004a51e66SJeff Dike if (err) { 351fee64d3cSJeff Dike printk(UM_KERN_ERR "maybe_sigio_broken - failed to add pollfd " 352fee64d3cSJeff Dike "for descriptor %d\n", fd); 35319bdf040SJeff Dike goto out; 35404a51e66SJeff Dike } 355838e56a1SJeff Dike 35619bdf040SJeff Dike all_sigio_fds.poll[all_sigio_fds.used++] = 35719bdf040SJeff Dike ((struct pollfd) { .fd = fd, 35819bdf040SJeff Dike .events = read ? POLLIN : POLLOUT, 35919bdf040SJeff Dike .revents = 0 }); 36019bdf040SJeff Dike out: 36119bdf040SJeff Dike sigio_unlock(); 3628e64d96aSJeff Dike } 3638e64d96aSJeff Dike 3645d33e4d7SJeff Dike /* Changed during early boot */ 3655d33e4d7SJeff Dike static int pty_output_sigio; 3665d33e4d7SJeff Dike static int pty_close_sigio; 3675d33e4d7SJeff Dike 3685d33e4d7SJeff Dike void maybe_sigio_broken(int fd, int read) 3695d33e4d7SJeff Dike { 3705d33e4d7SJeff Dike if (!isatty(fd)) 3715d33e4d7SJeff Dike return; 3725d33e4d7SJeff Dike 3735d33e4d7SJeff Dike if ((read || pty_output_sigio) && (!read || pty_close_sigio)) 3745d33e4d7SJeff Dike return; 3755d33e4d7SJeff Dike 3765d33e4d7SJeff Dike sigio_broken(fd, read); 3775d33e4d7SJeff Dike } 3785d33e4d7SJeff Dike 37929ac1c21SJeff Dike static void sigio_cleanup(void) 380f206aabbSJeff Dike { 381c4399016SJeff Dike if (write_sigio_pid == -1) 382c4399016SJeff Dike return; 383c4399016SJeff Dike 384f206aabbSJeff Dike os_kill_process(write_sigio_pid, 1); 385c4399016SJeff Dike free_stack(write_sigio_stack, 0); 386f206aabbSJeff Dike write_sigio_pid = -1; 387f206aabbSJeff Dike } 38829ac1c21SJeff Dike 38929ac1c21SJeff Dike __uml_exitcall(sigio_cleanup); 390c65badbdSJeff Dike 391c65badbdSJeff Dike /* Used as a flag during SIGIO testing early in boot */ 3925d33e4d7SJeff Dike static int got_sigio; 393c65badbdSJeff Dike 394c65badbdSJeff Dike static void __init handler(int sig) 395c65badbdSJeff Dike { 396c65badbdSJeff Dike got_sigio = 1; 397c65badbdSJeff Dike } 398c65badbdSJeff Dike 399c65badbdSJeff Dike struct openpty_arg { 400c65badbdSJeff Dike int master; 401c65badbdSJeff Dike int slave; 402c65badbdSJeff Dike int err; 403c65badbdSJeff Dike }; 404c65badbdSJeff Dike 405c65badbdSJeff Dike static void openpty_cb(void *arg) 406c65badbdSJeff Dike { 407c65badbdSJeff Dike struct openpty_arg *info = arg; 408c65badbdSJeff Dike 409c65badbdSJeff Dike info->err = 0; 410c65badbdSJeff Dike if (openpty(&info->master, &info->slave, NULL, NULL, NULL)) 411c65badbdSJeff Dike info->err = -errno; 412c65badbdSJeff Dike } 413c65badbdSJeff Dike 414c65badbdSJeff Dike static int async_pty(int master, int slave) 415c65badbdSJeff Dike { 416c65badbdSJeff Dike int flags; 417c65badbdSJeff Dike 418c65badbdSJeff Dike flags = fcntl(master, F_GETFL); 419c65badbdSJeff Dike if (flags < 0) 420c65badbdSJeff Dike return -errno; 421c65badbdSJeff Dike 422c65badbdSJeff Dike if ((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) || 423c65badbdSJeff Dike (fcntl(master, F_SETOWN, os_getpid()) < 0)) 424c65badbdSJeff Dike return -errno; 425c65badbdSJeff Dike 426c65badbdSJeff Dike if ((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0)) 427c65badbdSJeff Dike return -errno; 428c65badbdSJeff Dike 429c0a9290eSWANG Cong return 0; 430c65badbdSJeff Dike } 431c65badbdSJeff Dike 432c65badbdSJeff Dike static void __init check_one_sigio(void (*proc)(int, int)) 433c65badbdSJeff Dike { 434c65badbdSJeff Dike struct sigaction old, new; 435c65badbdSJeff Dike struct openpty_arg pty = { .master = -1, .slave = -1 }; 436c65badbdSJeff Dike int master, slave, err; 437c65badbdSJeff Dike 438c65badbdSJeff Dike initial_thread_cb(openpty_cb, &pty); 439c65badbdSJeff Dike if (pty.err) { 440fee64d3cSJeff Dike printk(UM_KERN_ERR "check_one_sigio failed, errno = %d\n", 441fee64d3cSJeff Dike -pty.err); 442c65badbdSJeff Dike return; 443c65badbdSJeff Dike } 444c65badbdSJeff Dike 445c65badbdSJeff Dike master = pty.master; 446c65badbdSJeff Dike slave = pty.slave; 447c65badbdSJeff Dike 448c65badbdSJeff Dike if ((master == -1) || (slave == -1)) { 449fee64d3cSJeff Dike printk(UM_KERN_ERR "check_one_sigio failed to allocate a " 450fee64d3cSJeff Dike "pty\n"); 451c65badbdSJeff Dike return; 452c65badbdSJeff Dike } 453c65badbdSJeff Dike 454c65badbdSJeff Dike /* Not now, but complain so we now where we failed. */ 455c65badbdSJeff Dike err = raw(master); 456fee64d3cSJeff Dike if (err < 0) { 457fee64d3cSJeff Dike printk(UM_KERN_ERR "check_one_sigio : raw failed, errno = %d\n", 458fee64d3cSJeff Dike -err); 459fee64d3cSJeff Dike return; 460fee64d3cSJeff Dike } 461c65badbdSJeff Dike 462c65badbdSJeff Dike err = async_pty(master, slave); 463fee64d3cSJeff Dike if (err < 0) { 464fee64d3cSJeff Dike printk(UM_KERN_ERR "check_one_sigio : sigio_async failed, " 465fee64d3cSJeff Dike "err = %d\n", -err); 466fee64d3cSJeff Dike return; 467fee64d3cSJeff Dike } 468c65badbdSJeff Dike 469fee64d3cSJeff Dike if (sigaction(SIGIO, NULL, &old) < 0) { 470fee64d3cSJeff Dike printk(UM_KERN_ERR "check_one_sigio : sigaction 1 failed, " 471fee64d3cSJeff Dike "errno = %d\n", errno); 472fee64d3cSJeff Dike return; 473fee64d3cSJeff Dike } 474fee64d3cSJeff Dike 475c65badbdSJeff Dike new = old; 476c65badbdSJeff Dike new.sa_handler = handler; 477fee64d3cSJeff Dike if (sigaction(SIGIO, &new, NULL) < 0) { 478fee64d3cSJeff Dike printk(UM_KERN_ERR "check_one_sigio : sigaction 2 failed, " 479fee64d3cSJeff Dike "errno = %d\n", errno); 480fee64d3cSJeff Dike return; 481fee64d3cSJeff Dike } 482c65badbdSJeff Dike 483c65badbdSJeff Dike got_sigio = 0; 484c65badbdSJeff Dike (*proc)(master, slave); 485c65badbdSJeff Dike 486c65badbdSJeff Dike close(master); 487c65badbdSJeff Dike close(slave); 488c65badbdSJeff Dike 489c65badbdSJeff Dike if (sigaction(SIGIO, &old, NULL) < 0) 490fee64d3cSJeff Dike printk(UM_KERN_ERR "check_one_sigio : sigaction 3 failed, " 491fee64d3cSJeff Dike "errno = %d\n", errno); 492c65badbdSJeff Dike } 493c65badbdSJeff Dike 494c65badbdSJeff Dike static void tty_output(int master, int slave) 495c65badbdSJeff Dike { 496c65badbdSJeff Dike int n; 497c65badbdSJeff Dike char buf[512]; 498c65badbdSJeff Dike 499fee64d3cSJeff Dike printk(UM_KERN_INFO "Checking that host ptys support output SIGIO..."); 500c65badbdSJeff Dike 501c65badbdSJeff Dike memset(buf, 0, sizeof(buf)); 502c65badbdSJeff Dike 503a61f334fSJeff Dike while (write(master, buf, sizeof(buf)) > 0) ; 504c65badbdSJeff Dike if (errno != EAGAIN) 505fee64d3cSJeff Dike printk(UM_KERN_ERR "tty_output : write failed, errno = %d\n", 506fee64d3cSJeff Dike errno); 5075d33e4d7SJeff Dike while (((n = read(slave, buf, sizeof(buf))) > 0) && 5085d33e4d7SJeff Dike !({ barrier(); got_sigio; })) 509fee64d3cSJeff Dike ; 510c65badbdSJeff Dike 511c65badbdSJeff Dike if (got_sigio) { 512fee64d3cSJeff Dike printk(UM_KERN_CONT "Yes\n"); 513c65badbdSJeff Dike pty_output_sigio = 1; 514fee64d3cSJeff Dike } else if (n == -EAGAIN) 515fee64d3cSJeff Dike printk(UM_KERN_CONT "No, enabling workaround\n"); 516fee64d3cSJeff Dike else 517fee64d3cSJeff Dike printk(UM_KERN_CONT "tty_output : read failed, err = %d\n", n); 518c65badbdSJeff Dike } 519c65badbdSJeff Dike 520c65badbdSJeff Dike static void tty_close(int master, int slave) 521c65badbdSJeff Dike { 522fee64d3cSJeff Dike printk(UM_KERN_INFO "Checking that host ptys support SIGIO on " 523fee64d3cSJeff Dike "close..."); 524c65badbdSJeff Dike 525c65badbdSJeff Dike close(slave); 526c65badbdSJeff Dike if (got_sigio) { 527fee64d3cSJeff Dike printk(UM_KERN_CONT "Yes\n"); 528c65badbdSJeff Dike pty_close_sigio = 1; 529fee64d3cSJeff Dike } else 530fee64d3cSJeff Dike printk(UM_KERN_CONT "No, enabling workaround\n"); 531c65badbdSJeff Dike } 532c65badbdSJeff Dike 533c65badbdSJeff Dike void __init check_sigio(void) 534c65badbdSJeff Dike { 535fee64d3cSJeff Dike if ((access("/dev/ptmx", R_OK) < 0) && 536fee64d3cSJeff Dike (access("/dev/ptyp0", R_OK) < 0)) { 537fee64d3cSJeff Dike printk(UM_KERN_WARNING "No pseudo-terminals available - " 538fee64d3cSJeff Dike "skipping pty SIGIO check\n"); 539c65badbdSJeff Dike return; 540c65badbdSJeff Dike } 541c65badbdSJeff Dike check_one_sigio(tty_output); 542c65badbdSJeff Dike check_one_sigio(tty_close); 543c65badbdSJeff Dike } 544c65badbdSJeff Dike 545c65badbdSJeff Dike /* Here because it only does the SIGIO testing for now */ 546c65badbdSJeff Dike void __init os_check_bugs(void) 547c65badbdSJeff Dike { 548c65badbdSJeff Dike check_sigio(); 549c65badbdSJeff Dike } 550