| 104 | | fd_set rset, wset, xset; |
| 105 | | GPollFD *f; |
| 106 | | int ready; |
| 107 | | int maxfd = 0; |
| 108 | | |
| 109 | | FD_ZERO (&rset); |
| 110 | | FD_ZERO (&wset); |
| 111 | | FD_ZERO (&xset); |
| 112 | | |
| 113 | | for (f = fds; f < &fds[nfds]; ++f) |
| 114 | | if (f->fd >= 0) |
| 115 | | { |
| 116 | | if (f->events & G_IO_IN) |
| 117 | | FD_SET (f->fd, &rset); |
| 118 | | if (f->events & G_IO_OUT) |
| 119 | | FD_SET (f->fd, &wset); |
| 120 | | if (f->events & G_IO_PRI) |
| 121 | | FD_SET (f->fd, &xset); |
| 122 | | if (f->fd > maxfd && (f->events & (G_IO_IN|G_IO_OUT|G_IO_PRI))) |
| 123 | | maxfd = f->fd; |
| 124 | | } |
| 125 | | tv.tv_sec = timeout / 1000; |
| 126 | | tv.tv_usec = (timeout % 1000) * 1000; |
| 127 | | |
| 128 | | ready = rb_thread_select (maxfd + 1, &rset, &wset, &xset, |
| 129 | | timeout == -1 ? NULL : &tv); |
| 130 | | if (ready > 0) |
| 131 | | for (f = fds; f < &fds[nfds]; ++f) |
| 132 | | { |
| 133 | | f->revents = 0; |
| 134 | | if (f->fd >= 0) |
| 135 | | { |
| 136 | | if (FD_ISSET (f->fd, &rset)) |
| 137 | | f->revents |= G_IO_IN; |
| 138 | | if (FD_ISSET (f->fd, &wset)) |
| 139 | | f->revents |= G_IO_OUT; |
| 140 | | if (FD_ISSET (f->fd, &xset)) |
| 141 | | f->revents |= G_IO_PRI; |
| 142 | | } |
| 143 | | } |
| 144 | | |
| 145 | | return ready; |
| 146 | | } |
| 147 | | |
| 148 | | #ifdef SHOES_GTK |
| | 111 | gettimeofday(&tv, NULL); |
| | 112 | return (double)tv.tv_sec + (double)tv.tv_usec * 1e-6; |
| | 113 | } |
| | 114 | |
| | 115 | typedef struct |
| | 116 | { |
| | 117 | GSource source; |
| | 118 | GList *poll_fds; |
| | 119 | gboolean ready; |
| | 120 | } shoes_source_t; |
| | 121 | |
| | 122 | static void |
| | 123 | source_free_poll_fds(GSource *source, gboolean source_is_destroyed) |
| | 124 | { |
| | 125 | shoes_source_t *shoes_source = (shoes_source_t *)source; |
| | 126 | GList *node; |
| | 127 | |
| | 128 | for (node = shoes_source->poll_fds; node; node = g_list_next(node)) { |
| | 129 | GPollFD *poll_fd = node->data; |
| | 130 | if (!source_is_destroyed) |
| | 131 | g_source_remove_poll(source, poll_fd); |
| | 132 | g_free(poll_fd); |
| | 133 | } |
| | 134 | g_list_free(shoes_source->poll_fds); |
| | 135 | shoes_source->poll_fds = NULL; |
| | 136 | } |
| | 137 | |
| | 138 | static inline void |
| | 139 | source_prepare_add_poll_fd(GSource *source, rb_thread_t thread) |
| | 140 | { |
| | 141 | shoes_source_t *shoes_source = (shoes_source_t *)source; |
| | 142 | GPollFD *poll_fd; |
| | 143 | |
| | 144 | poll_fd = g_new0(GPollFD, 1); |
| | 145 | poll_fd->fd = thread->fd; |
| | 146 | poll_fd->events = G_IO_IN; |
| | 147 | if (FD_ISSET(thread->fd, &thread->readfds)) |
| | 148 | poll_fd->events |= G_IO_IN; |
| | 149 | if (FD_ISSET(thread->fd, &thread->writefds)) |
| | 150 | poll_fd->events |= G_IO_OUT; |
| | 151 | if (FD_ISSET(thread->fd, &thread->exceptfds)) |
| | 152 | poll_fd->events |= G_IO_PRI | G_IO_ERR | G_IO_HUP; |
| | 153 | |
| | 154 | g_source_add_poll(source, poll_fd); |
| | 155 | shoes_source->poll_fds = g_list_prepend(shoes_source->poll_fds, poll_fd); |
| | 156 | } |
| | 157 | |
| | 158 | static inline gboolean |
| | 159 | source_prepare_setup_poll_fd(GSource *source, gint *timeout) |
| | 160 | { |
| | 161 | rb_thread_t thread; |
| | 162 | gdouble now; |
| | 163 | |
| | 164 | now = timeofday(); |
| | 165 | thread = curr_thread; |
| | 166 | do { |
| | 167 | thread = thread->next; |
| | 168 | |
| | 169 | if ((thread->wait_for == 0 && thread->status == THREAD_RUNNABLE && |
| | 170 | thread != curr_thread) || |
| | 171 | (thread->wait_for & WAIT_JOIN && |
| | 172 | thread->join->status == THREAD_KILLED)) |
| | 173 | return TRUE; |
| | 174 | |
| | 175 | if (thread->wait_for & WAIT_TIME && thread->delay != DELAY_INFTY) { |
| | 176 | gint delay; |
| | 177 | |
| | 178 | delay = (thread->delay - now) * 1000; |
| | 179 | if (delay <= 0) |
| | 180 | return TRUE; |
| | 181 | if (*timeout == -1 || delay < *timeout) |
| | 182 | *timeout = delay; |
| | 183 | } |
| | 184 | |
| | 185 | if (thread->wait_for & WAIT_FD) |
| | 186 | source_prepare_add_poll_fd(source, thread); |
| | 187 | } while (thread != curr_thread); |
| | 188 | |
| | 189 | return FALSE; |
| | 190 | } |
| | 191 | |
| | 192 | static gboolean |
| | 193 | source_prepare(GSource *source, gint *timeout) |
| | 194 | { |
| | 195 | shoes_source_t *shoes_source = (shoes_source_t *)source; |
| | 196 | |
| | 197 | *timeout = -1; |
| | 198 | source_free_poll_fds(source, FALSE); |
| | 199 | shoes_source->ready = source_prepare_setup_poll_fd(source, timeout); |
| | 200 | |
| | 201 | return shoes_source->ready; |
| | 202 | } |
| | 203 | |
| | 204 | static gboolean |
| | 205 | source_check(GSource *source) |
| | 206 | { |
| | 207 | shoes_source_t *shoes_source = (shoes_source_t *)source; |
| | 208 | GList *node; |
| | 209 | |
| | 210 | if (shoes_source->ready) |
| | 211 | return TRUE; |
| | 212 | |
| | 213 | for (node = shoes_source->poll_fds; node; node = g_list_next(node)) { |
| | 214 | GPollFD *poll_fd = node->data; |
| | 215 | |
| | 216 | if (poll_fd->revents) |
| | 217 | return TRUE; |
| | 218 | } |
| | 219 | |
| | 220 | return FALSE; |
| | 221 | } |
| | 222 | |
| | 223 | static gboolean |
| | 224 | source_dispatch(GSource *source, GSourceFunc callback, gpointer user_data) |
| | 225 | { |
| | 226 | TRAP_BEG; |
| | 227 | rb_thread_schedule(); |
| | 228 | TRAP_END; |
| | 229 | |
| | 230 | return TRUE; |
| | 231 | } |
| | 232 | |
| | 233 | static void |
| | 234 | source_finalize(GSource *source) |
| | 235 | { |
| | 236 | source_free_poll_fds(source, TRUE); |
| | 237 | } |
| | 238 | |
| | 239 | static GSourceFuncs source_funcs = { |
| | 240 | source_prepare, |
| | 241 | source_check, |
| | 242 | source_dispatch, |
| | 243 | source_finalize |
| | 244 | }; |
| | 245 | |