1 /* 2 * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 3 * Licensed under the GPL 4 */ 5 6 #include <stdlib.h> 7 #include <errno.h> 8 #include <poll.h> 9 #include <signal.h> 10 #include <string.h> 11 #include "irq_user.h" 12 #include "kern_constants.h" 13 #include "os.h" 14 #include "process.h" 15 #include "um_malloc.h" 16 #include "user.h" 17 18 /* 19 * Locked by irq_lock in arch/um/kernel/irq.c. Changed by os_create_pollfd 20 * and os_free_irq_by_cb, which are called under irq_lock. 21 */ 22 static struct pollfd *pollfds = NULL; 23 static int pollfds_num = 0; 24 static int pollfds_size = 0; 25 26 int os_waiting_for_events(struct irq_fd *active_fds) 27 { 28 struct irq_fd *irq_fd; 29 int i, n, err; 30 31 n = poll(pollfds, pollfds_num, 0); 32 if (n < 0) { 33 err = -errno; 34 if (errno != EINTR) 35 printk(UM_KERN_ERR "os_waiting_for_events:" 36 " poll returned %d, errno = %d\n", n, errno); 37 return err; 38 } 39 40 if (n == 0) 41 return 0; 42 43 irq_fd = active_fds; 44 45 for (i = 0; i < pollfds_num; i++) { 46 if (pollfds[i].revents != 0) { 47 irq_fd->current_events = pollfds[i].revents; 48 pollfds[i].fd = -1; 49 } 50 irq_fd = irq_fd->next; 51 } 52 return n; 53 } 54 55 int os_create_pollfd(int fd, int events, void *tmp_pfd, int size_tmpfds) 56 { 57 if (pollfds_num == pollfds_size) { 58 if (size_tmpfds <= pollfds_size * sizeof(pollfds[0])) { 59 /* return min size needed for new pollfds area */ 60 return (pollfds_size + 1) * sizeof(pollfds[0]); 61 } 62 63 if (pollfds != NULL) { 64 memcpy(tmp_pfd, pollfds, 65 sizeof(pollfds[0]) * pollfds_size); 66 /* remove old pollfds */ 67 kfree(pollfds); 68 } 69 pollfds = tmp_pfd; 70 pollfds_size++; 71 } else 72 kfree(tmp_pfd); /* remove not used tmp_pfd */ 73 74 pollfds[pollfds_num] = ((struct pollfd) { .fd = fd, 75 .events = events, 76 .revents = 0 }); 77 pollfds_num++; 78 79 return 0; 80 } 81 82 void os_free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg, 83 struct irq_fd *active_fds, struct irq_fd ***last_irq_ptr2) 84 { 85 struct irq_fd **prev; 86 int i = 0; 87 88 prev = &active_fds; 89 while (*prev != NULL) { 90 if ((*test)(*prev, arg)) { 91 struct irq_fd *old_fd = *prev; 92 if ((pollfds[i].fd != -1) && 93 (pollfds[i].fd != (*prev)->fd)) { 94 printk(UM_KERN_ERR "os_free_irq_by_cb - " 95 "mismatch between active_fds and " 96 "pollfds, fd %d vs %d\n", 97 (*prev)->fd, pollfds[i].fd); 98 goto out; 99 } 100 101 pollfds_num--; 102 103 /* 104 * This moves the *whole* array after pollfds[i] 105 * (though it doesn't spot as such)! 106 */ 107 memmove(&pollfds[i], &pollfds[i + 1], 108 (pollfds_num - i) * sizeof(pollfds[0])); 109 if (*last_irq_ptr2 == &old_fd->next) 110 *last_irq_ptr2 = prev; 111 112 *prev = (*prev)->next; 113 if (old_fd->type == IRQ_WRITE) 114 ignore_sigio_fd(old_fd->fd); 115 kfree(old_fd); 116 continue; 117 } 118 prev = &(*prev)->next; 119 i++; 120 } 121 out: 122 return; 123 } 124 125 int os_get_pollfd(int i) 126 { 127 return pollfds[i].fd; 128 } 129 130 void os_set_pollfd(int i, int fd) 131 { 132 pollfds[i].fd = fd; 133 } 134 135 void os_set_ioignore(void) 136 { 137 signal(SIGIO, SIG_IGN); 138 } 139