Changeset 484

Show
Ignore:
Timestamp:
03/15/2008 16:36:40 (6 months ago)
Author:
why
Message:
  • shoes/app.c: using g_source_attach rather than hooking the main loop. i know it's more expensive this way, but the other way just simply wouldn't fire repaints. when we move to ruby 1.9, i'll use rb_thread_blocking_region instead.
Files:
1 modified

Legend:

Unmodified
Added
Removed
  • trunk/shoes/app.c

    r483 r484  
    9696} 
    9797 
    98 static gint                                                                                                                    
    99 shoes_app_g_poll (GPollFD *fds, 
    100            guint    nfds, 
    101            gint     timeout) 
     98#ifdef SHOES_GTK 
     99#define WAIT_FD   (1<<0) 
     100#define WAIT_SELECT (1<<1) 
     101#define WAIT_TIME (1<<2) 
     102#define WAIT_JOIN (1<<3) 
     103#define WAIT_PID  (1<<4) 
     104 
     105#define DELAY_INFTY 1E30 
     106 
     107static double 
     108timeofday() 
    102109{ 
    103110    struct timeval tv; 
    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 
     115typedef struct 
     116{ 
     117    GSource source; 
     118    GList *poll_fds; 
     119    gboolean ready; 
     120} shoes_source_t; 
     121 
     122static void 
     123source_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 
     138static inline void 
     139source_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 
     158static inline gboolean 
     159source_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 
     192static gboolean 
     193source_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 
     204static gboolean 
     205source_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 
     223static gboolean 
     224source_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 
     233static void 
     234source_finalize(GSource *source) 
     235{ 
     236    source_free_poll_fds(source, TRUE); 
     237} 
     238 
     239static GSourceFuncs source_funcs = { 
     240    source_prepare, 
     241    source_check, 
     242    source_dispatch, 
     243    source_finalize 
     244}; 
     245 
    149246static VALUE 
    150247shoes_app_gtk_exception(VALUE v, VALUE exc) 
     
    17221819 
    17231820#ifdef SHOES_GTK 
    1724   g_main_set_poll_func(shoes_app_g_poll); 
     1821  GSource *source; 
     1822  guint tag; 
     1823  shoes_source_t *shoes_source; 
     1824 
     1825  source = g_source_new(&source_funcs, sizeof(shoes_source_t)); 
     1826  g_source_set_can_recurse(source, TRUE); 
     1827 
     1828  shoes_source = (shoes_source_t *)source; 
     1829  shoes_source->poll_fds = NULL; 
     1830 
     1831  tag = g_source_attach(source, NULL); 
     1832  g_source_unref(source); 
     1833  rb_set_end_proc((void (*)(VALUE))g_source_remove, (VALUE)tag); 
     1834 
    17251835  gtk_main(); 
    17261836#endif