1f206aabbSJeff Dike /* 2f206aabbSJeff Dike * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) 3f206aabbSJeff Dike * Licensed under the GPL 4f206aabbSJeff Dike */ 5f206aabbSJeff Dike 6f206aabbSJeff Dike #include <unistd.h> 7f206aabbSJeff Dike #include <stdlib.h> 8f206aabbSJeff Dike #include <termios.h> 9f206aabbSJeff Dike #include <pty.h> 10f206aabbSJeff Dike #include <signal.h> 11f206aabbSJeff Dike #include <errno.h> 12f206aabbSJeff Dike #include <string.h> 13f206aabbSJeff Dike #include <sched.h> 14f206aabbSJeff Dike #include <sys/socket.h> 15f206aabbSJeff Dike #include <sys/poll.h> 16f206aabbSJeff Dike #include "init.h" 17f206aabbSJeff Dike #include "user.h" 18f206aabbSJeff Dike #include "kern_util.h" 19f206aabbSJeff Dike #include "user_util.h" 20f206aabbSJeff Dike #include "sigio.h" 21f206aabbSJeff Dike #include "os.h" 22f206aabbSJeff Dike 23f206aabbSJeff Dike /* Protected by sigio_lock(), also used by sigio_cleanup, which is an 24f206aabbSJeff Dike * exitcall. 25f206aabbSJeff Dike */ 26f206aabbSJeff Dike static int write_sigio_pid = -1; 27f206aabbSJeff Dike 28f206aabbSJeff Dike /* These arrays are initialized before the sigio thread is started, and 29f206aabbSJeff Dike * the descriptors closed after it is killed. So, it can't see them change. 30f206aabbSJeff Dike * On the UML side, they are changed under the sigio_lock. 31f206aabbSJeff Dike */ 32*5f4e8fd0SJeff Dike #define SIGIO_FDS_INIT {-1, -1} 33*5f4e8fd0SJeff Dike 34*5f4e8fd0SJeff Dike static int write_sigio_fds[2] = SIGIO_FDS_INIT; 35*5f4e8fd0SJeff Dike static int sigio_private[2] = SIGIO_FDS_INIT; 36f206aabbSJeff Dike 37f206aabbSJeff Dike struct pollfds { 38f206aabbSJeff Dike struct pollfd *poll; 39f206aabbSJeff Dike int size; 40f206aabbSJeff Dike int used; 41f206aabbSJeff Dike }; 42f206aabbSJeff Dike 43f206aabbSJeff Dike /* Protected by sigio_lock(). Used by the sigio thread, but the UML thread 44f206aabbSJeff Dike * synchronizes with it. 45f206aabbSJeff Dike */ 46f206aabbSJeff Dike struct pollfds current_poll = { 47f206aabbSJeff Dike .poll = NULL, 48f206aabbSJeff Dike .size = 0, 49f206aabbSJeff Dike .used = 0 50f206aabbSJeff Dike }; 51f206aabbSJeff Dike 52f206aabbSJeff Dike struct pollfds next_poll = { 53f206aabbSJeff Dike .poll = NULL, 54f206aabbSJeff Dike .size = 0, 55f206aabbSJeff Dike .used = 0 56f206aabbSJeff Dike }; 57f206aabbSJeff Dike 58f206aabbSJeff Dike static int write_sigio_thread(void *unused) 59f206aabbSJeff Dike { 60f206aabbSJeff Dike struct pollfds *fds, tmp; 61f206aabbSJeff Dike struct pollfd *p; 62f206aabbSJeff Dike int i, n, respond_fd; 63f206aabbSJeff Dike char c; 64f206aabbSJeff Dike 65f206aabbSJeff Dike signal(SIGWINCH, SIG_IGN); 66f206aabbSJeff Dike fds = ¤t_poll; 67f206aabbSJeff Dike while(1){ 68f206aabbSJeff Dike n = poll(fds->poll, fds->used, -1); 69f206aabbSJeff Dike if(n < 0){ 70f206aabbSJeff Dike if(errno == EINTR) continue; 71f206aabbSJeff Dike printk("write_sigio_thread : poll returned %d, " 72f206aabbSJeff Dike "errno = %d\n", n, errno); 73f206aabbSJeff Dike } 74f206aabbSJeff Dike for(i = 0; i < fds->used; i++){ 75f206aabbSJeff Dike p = &fds->poll[i]; 76f206aabbSJeff Dike if(p->revents == 0) continue; 77f206aabbSJeff Dike if(p->fd == sigio_private[1]){ 78f206aabbSJeff Dike n = os_read_file(sigio_private[1], &c, sizeof(c)); 79f206aabbSJeff Dike if(n != sizeof(c)) 80f206aabbSJeff Dike printk("write_sigio_thread : " 81f206aabbSJeff Dike "read failed, err = %d\n", -n); 82f206aabbSJeff Dike tmp = current_poll; 83f206aabbSJeff Dike current_poll = next_poll; 84f206aabbSJeff Dike next_poll = tmp; 85f206aabbSJeff Dike respond_fd = sigio_private[1]; 86f206aabbSJeff Dike } 87f206aabbSJeff Dike else { 88f206aabbSJeff Dike respond_fd = write_sigio_fds[1]; 89f206aabbSJeff Dike fds->used--; 90f206aabbSJeff Dike memmove(&fds->poll[i], &fds->poll[i + 1], 91f206aabbSJeff Dike (fds->used - i) * sizeof(*fds->poll)); 92f206aabbSJeff Dike } 93f206aabbSJeff Dike 94f206aabbSJeff Dike n = os_write_file(respond_fd, &c, sizeof(c)); 95f206aabbSJeff Dike if(n != sizeof(c)) 96f206aabbSJeff Dike printk("write_sigio_thread : write failed, " 97f206aabbSJeff Dike "err = %d\n", -n); 98f206aabbSJeff Dike } 99f206aabbSJeff Dike } 100f206aabbSJeff Dike 101f206aabbSJeff Dike return 0; 102f206aabbSJeff Dike } 103f206aabbSJeff Dike 104f206aabbSJeff Dike static int need_poll(int n) 105f206aabbSJeff Dike { 106f206aabbSJeff Dike if(n <= next_poll.size){ 107f206aabbSJeff Dike next_poll.used = n; 108f206aabbSJeff Dike return(0); 109f206aabbSJeff Dike } 110f206aabbSJeff Dike kfree(next_poll.poll); 111f206aabbSJeff Dike next_poll.poll = um_kmalloc_atomic(n * sizeof(struct pollfd)); 112f206aabbSJeff Dike if(next_poll.poll == NULL){ 113f206aabbSJeff Dike printk("need_poll : failed to allocate new pollfds\n"); 114f206aabbSJeff Dike next_poll.size = 0; 115f206aabbSJeff Dike next_poll.used = 0; 116f206aabbSJeff Dike return(-1); 117f206aabbSJeff Dike } 118f206aabbSJeff Dike next_poll.size = n; 119f206aabbSJeff Dike next_poll.used = n; 120f206aabbSJeff Dike return(0); 121f206aabbSJeff Dike } 122f206aabbSJeff Dike 123f206aabbSJeff Dike /* Must be called with sigio_lock held, because it's needed by the marked 124f206aabbSJeff Dike * critical section. */ 125f206aabbSJeff Dike static void update_thread(void) 126f206aabbSJeff Dike { 127f206aabbSJeff Dike unsigned long flags; 128f206aabbSJeff Dike int n; 129f206aabbSJeff Dike char c; 130f206aabbSJeff Dike 131f206aabbSJeff Dike flags = set_signals(0); 132f206aabbSJeff Dike n = os_write_file(sigio_private[0], &c, sizeof(c)); 133f206aabbSJeff Dike if(n != sizeof(c)){ 134f206aabbSJeff Dike printk("update_thread : write failed, err = %d\n", -n); 135f206aabbSJeff Dike goto fail; 136f206aabbSJeff Dike } 137f206aabbSJeff Dike 138f206aabbSJeff Dike n = os_read_file(sigio_private[0], &c, sizeof(c)); 139f206aabbSJeff Dike if(n != sizeof(c)){ 140f206aabbSJeff Dike printk("update_thread : read failed, err = %d\n", -n); 141f206aabbSJeff Dike goto fail; 142f206aabbSJeff Dike } 143f206aabbSJeff Dike 144f206aabbSJeff Dike set_signals(flags); 145f206aabbSJeff Dike return; 146f206aabbSJeff Dike fail: 147f206aabbSJeff Dike /* Critical section start */ 148f206aabbSJeff Dike if(write_sigio_pid != -1) 149f206aabbSJeff Dike os_kill_process(write_sigio_pid, 1); 150f206aabbSJeff Dike write_sigio_pid = -1; 151f206aabbSJeff Dike close(sigio_private[0]); 152f206aabbSJeff Dike close(sigio_private[1]); 153f206aabbSJeff Dike close(write_sigio_fds[0]); 154f206aabbSJeff Dike close(write_sigio_fds[1]); 155f206aabbSJeff Dike /* Critical section end */ 156f206aabbSJeff Dike set_signals(flags); 157f206aabbSJeff Dike } 158f206aabbSJeff Dike 159f206aabbSJeff Dike int add_sigio_fd(int fd, int read) 160f206aabbSJeff Dike { 161f206aabbSJeff Dike int err = 0, i, n, events; 162f206aabbSJeff Dike 163f206aabbSJeff Dike sigio_lock(); 164f206aabbSJeff Dike for(i = 0; i < current_poll.used; i++){ 165f206aabbSJeff Dike if(current_poll.poll[i].fd == fd) 166f206aabbSJeff Dike goto out; 167f206aabbSJeff Dike } 168f206aabbSJeff Dike 169f206aabbSJeff Dike n = current_poll.used + 1; 170f206aabbSJeff Dike err = need_poll(n); 171f206aabbSJeff Dike if(err) 172f206aabbSJeff Dike goto out; 173f206aabbSJeff Dike 174f206aabbSJeff Dike for(i = 0; i < current_poll.used; i++) 175f206aabbSJeff Dike next_poll.poll[i] = current_poll.poll[i]; 176f206aabbSJeff Dike 177f206aabbSJeff Dike if(read) events = POLLIN; 178f206aabbSJeff Dike else events = POLLOUT; 179f206aabbSJeff Dike 180f206aabbSJeff Dike next_poll.poll[n - 1] = ((struct pollfd) { .fd = fd, 181f206aabbSJeff Dike .events = events, 182f206aabbSJeff Dike .revents = 0 }); 183f206aabbSJeff Dike update_thread(); 184f206aabbSJeff Dike out: 185f206aabbSJeff Dike sigio_unlock(); 186f206aabbSJeff Dike return(err); 187f206aabbSJeff Dike } 188f206aabbSJeff Dike 189f206aabbSJeff Dike int ignore_sigio_fd(int fd) 190f206aabbSJeff Dike { 191f206aabbSJeff Dike struct pollfd *p; 192f206aabbSJeff Dike int err = 0, i, n = 0; 193f206aabbSJeff Dike 194f206aabbSJeff Dike sigio_lock(); 195f206aabbSJeff Dike for(i = 0; i < current_poll.used; i++){ 196f206aabbSJeff Dike if(current_poll.poll[i].fd == fd) break; 197f206aabbSJeff Dike } 198f206aabbSJeff Dike if(i == current_poll.used) 199f206aabbSJeff Dike goto out; 200f206aabbSJeff Dike 201f206aabbSJeff Dike err = need_poll(current_poll.used - 1); 202f206aabbSJeff Dike if(err) 203f206aabbSJeff Dike goto out; 204f206aabbSJeff Dike 205f206aabbSJeff Dike for(i = 0; i < current_poll.used; i++){ 206f206aabbSJeff Dike p = ¤t_poll.poll[i]; 207f206aabbSJeff Dike if(p->fd != fd) next_poll.poll[n++] = current_poll.poll[i]; 208f206aabbSJeff Dike } 209f206aabbSJeff Dike if(n == i){ 210f206aabbSJeff Dike printk("ignore_sigio_fd : fd %d not found\n", fd); 211f206aabbSJeff Dike err = -1; 212f206aabbSJeff Dike goto out; 213f206aabbSJeff Dike } 214f206aabbSJeff Dike 215f206aabbSJeff Dike update_thread(); 216f206aabbSJeff Dike out: 217f206aabbSJeff Dike sigio_unlock(); 218f206aabbSJeff Dike return(err); 219f206aabbSJeff Dike } 220f206aabbSJeff Dike 221f206aabbSJeff Dike static struct pollfd *setup_initial_poll(int fd) 222f206aabbSJeff Dike { 223f206aabbSJeff Dike struct pollfd *p; 224f206aabbSJeff Dike 225f206aabbSJeff Dike p = um_kmalloc(sizeof(struct pollfd)); 226f206aabbSJeff Dike if (p == NULL) { 227f206aabbSJeff Dike printk("setup_initial_poll : failed to allocate poll\n"); 228f206aabbSJeff Dike return NULL; 229f206aabbSJeff Dike } 230f206aabbSJeff Dike *p = ((struct pollfd) { .fd = fd, 231f206aabbSJeff Dike .events = POLLIN, 232f206aabbSJeff Dike .revents = 0 }); 233f206aabbSJeff Dike return p; 234f206aabbSJeff Dike } 235f206aabbSJeff Dike 236f206aabbSJeff Dike void write_sigio_workaround(void) 237f206aabbSJeff Dike { 238f206aabbSJeff Dike unsigned long stack; 239f206aabbSJeff Dike struct pollfd *p; 240f206aabbSJeff Dike int err; 241f206aabbSJeff Dike int l_write_sigio_fds[2]; 242f206aabbSJeff Dike int l_sigio_private[2]; 243f206aabbSJeff Dike int l_write_sigio_pid; 244f206aabbSJeff Dike 245f206aabbSJeff Dike /* We call this *tons* of times - and most ones we must just fail. */ 246f206aabbSJeff Dike sigio_lock(); 247f206aabbSJeff Dike l_write_sigio_pid = write_sigio_pid; 248f206aabbSJeff Dike sigio_unlock(); 249f206aabbSJeff Dike 250f206aabbSJeff Dike if (l_write_sigio_pid != -1) 251f206aabbSJeff Dike return; 252f206aabbSJeff Dike 253f206aabbSJeff Dike err = os_pipe(l_write_sigio_fds, 1, 1); 254f206aabbSJeff Dike if(err < 0){ 255f206aabbSJeff Dike printk("write_sigio_workaround - os_pipe 1 failed, " 256f206aabbSJeff Dike "err = %d\n", -err); 257f206aabbSJeff Dike return; 258f206aabbSJeff Dike } 259f206aabbSJeff Dike err = os_pipe(l_sigio_private, 1, 1); 260f206aabbSJeff Dike if(err < 0){ 261f206aabbSJeff Dike printk("write_sigio_workaround - os_pipe 2 failed, " 262f206aabbSJeff Dike "err = %d\n", -err); 263f206aabbSJeff Dike goto out_close1; 264f206aabbSJeff Dike } 265f206aabbSJeff Dike 266f206aabbSJeff Dike p = setup_initial_poll(l_sigio_private[1]); 267f206aabbSJeff Dike if(!p) 268f206aabbSJeff Dike goto out_close2; 269f206aabbSJeff Dike 270f206aabbSJeff Dike sigio_lock(); 271f206aabbSJeff Dike 272f206aabbSJeff Dike /* Did we race? Don't try to optimize this, please, it's not so likely 273f206aabbSJeff Dike * to happen, and no more than once at the boot. */ 274f206aabbSJeff Dike if(write_sigio_pid != -1) 275*5f4e8fd0SJeff Dike goto out_free; 276*5f4e8fd0SJeff Dike 277*5f4e8fd0SJeff Dike current_poll = ((struct pollfds) { .poll = p, 278*5f4e8fd0SJeff Dike .used = 1, 279*5f4e8fd0SJeff Dike .size = 1 }); 280*5f4e8fd0SJeff Dike 281*5f4e8fd0SJeff Dike if (write_sigio_irq(l_write_sigio_fds[0])) 282*5f4e8fd0SJeff Dike goto out_clear_poll; 283*5f4e8fd0SJeff Dike 284*5f4e8fd0SJeff Dike memcpy(write_sigio_fds, l_write_sigio_fds, sizeof(l_write_sigio_fds)); 285*5f4e8fd0SJeff Dike memcpy(sigio_private, l_sigio_private, sizeof(l_sigio_private)); 286f206aabbSJeff Dike 287f206aabbSJeff Dike write_sigio_pid = run_helper_thread(write_sigio_thread, NULL, 288f206aabbSJeff Dike CLONE_FILES | CLONE_VM, &stack, 0); 289f206aabbSJeff Dike 290f206aabbSJeff Dike if (write_sigio_pid < 0) 291f206aabbSJeff Dike goto out_clear; 292f206aabbSJeff Dike 293f206aabbSJeff Dike sigio_unlock(); 294f206aabbSJeff Dike return; 295f206aabbSJeff Dike 296f206aabbSJeff Dike out_clear: 297f206aabbSJeff Dike write_sigio_pid = -1; 298*5f4e8fd0SJeff Dike write_sigio_fds[0] = -1; 299*5f4e8fd0SJeff Dike write_sigio_fds[1] = -1; 300*5f4e8fd0SJeff Dike sigio_private[0] = -1; 301*5f4e8fd0SJeff Dike sigio_private[1] = -1; 302*5f4e8fd0SJeff Dike out_clear_poll: 303*5f4e8fd0SJeff Dike current_poll = ((struct pollfds) { .poll = NULL, 304*5f4e8fd0SJeff Dike .size = 0, 305*5f4e8fd0SJeff Dike .used = 0 }); 306f206aabbSJeff Dike out_free: 307f206aabbSJeff Dike kfree(p); 308*5f4e8fd0SJeff Dike sigio_unlock(); 309f206aabbSJeff Dike out_close2: 310f206aabbSJeff Dike close(l_sigio_private[0]); 311f206aabbSJeff Dike close(l_sigio_private[1]); 312f206aabbSJeff Dike out_close1: 313f206aabbSJeff Dike close(l_write_sigio_fds[0]); 314f206aabbSJeff Dike close(l_write_sigio_fds[1]); 315f206aabbSJeff Dike } 316f206aabbSJeff Dike 317f206aabbSJeff Dike void sigio_cleanup(void) 318f206aabbSJeff Dike { 319f206aabbSJeff Dike if(write_sigio_pid != -1){ 320f206aabbSJeff Dike os_kill_process(write_sigio_pid, 1); 321f206aabbSJeff Dike write_sigio_pid = -1; 322f206aabbSJeff Dike } 323f206aabbSJeff Dike } 324