| 81 | | } |
| 82 | | |
| 83 | | /* Returns the index of the dispatch for the file descriptor. */ |
| 84 | | int owl_select_find_dispatch(int fd) |
| 85 | | { |
| 86 | | int i, len; |
| 87 | | const owl_list *dl; |
| 88 | | const owl_dispatch *d; |
| 89 | | |
| 90 | | dl = owl_global_get_dispatchlist(&g); |
| 91 | | len = owl_list_get_size(dl); |
| 92 | | for(i = 0; i < len; i++) { |
| 93 | | d = owl_list_get_element(dl, i); |
| 94 | | if (d->fd == fd) return i; |
| 95 | | } |
| 96 | | return -1; |
| 97 | | } |
| 98 | | |
| 99 | | void owl_select_remove_dispatch_at(int elt) /* noproto */ |
| 100 | | { |
| 101 | | owl_list *dl; |
| 102 | | owl_dispatch *d; |
| 103 | | |
| 104 | | dl = owl_global_get_dispatchlist(&g); |
| 105 | | d = owl_list_get_element(dl, elt); |
| 106 | | owl_list_remove_element(dl, elt); |
| 107 | | if (d->destroy) { |
| 108 | | d->destroy(d); |
| 109 | | } |
| 110 | | } |
| 111 | | |
| 112 | | /* Adds a new owl_dispatch to the list, replacing existing ones if needed. */ |
| 113 | | void owl_select_add_dispatch(owl_dispatch *d) |
| 114 | | { |
| 115 | | int elt; |
| 116 | | owl_list *dl; |
| 117 | | |
| 118 | | d->needs_gc = 0; |
| 119 | | |
| 120 | | elt = owl_select_find_dispatch(d->fd); |
| 121 | | dl = owl_global_get_dispatchlist(&g); |
| 122 | | |
| 123 | | if (elt != -1) { /* If we have a dispatch for this FD */ |
| 124 | | owl_dispatch *d_old; |
| 125 | | d_old = owl_list_get_element(dl, elt); |
| 126 | | /* Ignore if we're adding the same dispatch again. Otherwise |
| 127 | | replace the old dispatch. */ |
| 128 | | if (d_old != d) { |
| 129 | | owl_select_remove_dispatch_at(elt); |
| 130 | | } |
| 131 | | } |
| 132 | | owl_list_append_element(dl, d); |
| 133 | | } |
| 134 | | |
| 135 | | /* Removes an owl_dispatch to the list, based on it's file descriptor. */ |
| 136 | | void owl_select_remove_dispatch(int fd) |
| 137 | | { |
| 138 | | int elt; |
| 139 | | owl_list *dl; |
| 140 | | owl_dispatch *d; |
| 141 | | |
| 142 | | elt = owl_select_find_dispatch(fd); |
| 143 | | if(elt == -1) { |
| 144 | | return; |
| 145 | | } else if(dispatch_active) { |
| 146 | | /* Defer the removal until dispatch is done walking the list */ |
| 147 | | dl = owl_global_get_dispatchlist(&g); |
| 148 | | d = owl_list_get_element(dl, elt); |
| 149 | | d->needs_gc = 1; |
| 150 | | } else { |
| 151 | | owl_select_remove_dispatch_at(elt); |
| 152 | | } |
| 153 | | } |
| 154 | | |
| 155 | | int owl_select_dispatch_count(void) |
| 156 | | { |
| 157 | | return owl_list_get_size(owl_global_get_dispatchlist(&g)); |
| 158 | | } |
| 159 | | |
| 160 | | int owl_select_dispatch_prepare_fd_sets(fd_set *r, fd_set *e) |
| 161 | | { |
| 162 | | int i, len, max_fd; |
| 163 | | owl_dispatch *d; |
| 164 | | const owl_list *dl; |
| 165 | | |
| 166 | | dl = owl_global_get_dispatchlist(&g); |
| 167 | | max_fd = 0; |
| 168 | | len = owl_select_dispatch_count(); |
| 169 | | for(i = 0; i < len; i++) { |
| 170 | | d = owl_list_get_element(dl, i); |
| 171 | | FD_SET(d->fd, r); |
| 172 | | FD_SET(d->fd, e); |
| 173 | | if (max_fd < d->fd) max_fd = d->fd; |
| 174 | | } |
| 175 | | return max_fd + 1; |
| 176 | | } |
| 177 | | |
| 178 | | void owl_select_gc(void) |
| 179 | | { |
| 180 | | int i; |
| 181 | | owl_list *dl; |
| 182 | | |
| 183 | | dl = owl_global_get_dispatchlist(&g); |
| 184 | | /* |
| 185 | | * Count down so we aren't set off by removing items from the list |
| 186 | | * during the iteration. |
| 187 | | */ |
| 188 | | for(i = owl_list_get_size(dl) - 1; i >= 0; i--) { |
| 189 | | const owl_dispatch *d = owl_list_get_element(dl, i); |
| 190 | | if(d->needs_gc) { |
| 191 | | owl_select_remove_dispatch_at(i); |
| 192 | | } |
| 193 | | } |
| 194 | | } |
| 195 | | |
| 196 | | void owl_select_dispatch(fd_set *fds, int max_fd) |
| 197 | | { |
| 198 | | int i, len; |
| 199 | | owl_dispatch *d; |
| 200 | | const owl_list *dl; |
| 201 | | |
| 202 | | dl = owl_global_get_dispatchlist(&g); |
| 203 | | len = owl_select_dispatch_count(); |
| 204 | | |
| 205 | | dispatch_active = 1; |
| 206 | | |
| 207 | | for(i = 0; i < len; i++) { |
| 208 | | d = owl_list_get_element(dl, i); |
| 209 | | /* While d shouldn't normally be null, the list may be altered by |
| 210 | | * functions we dispatch to. */ |
| 211 | | if (d != NULL && !d->needs_gc && FD_ISSET(d->fd, fds)) { |
| 212 | | if (d->cfunc != NULL) { |
| 213 | | d->cfunc(d); |
| 214 | | } |
| 215 | | } |
| 216 | | } |
| 217 | | |
| 218 | | dispatch_active = 0; |
| 219 | | owl_select_gc(); |