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