#include #include #include #include #include #include #include #include #define exit_if_fail(c) { \ if (!(c)) { \ fprintf (stderr, "%s(%d) '%s' failed.\n", __FUNCTION__, __LINE__, #c); \ exit (-1); \ } \ } static void sync_callback(void *data, struct wl_callback *callback, uint32_t serial) { wl_callback_destroy (callback); } static const struct wl_callback_listener sync_listener = { sync_callback }; void* thread_sub (void *data) { struct wl_display *display = (struct wl_display*)data; struct wl_event_queue *queue; struct pollfd fds; int ret; /* make sure that display is created */ while (!display) usleep (10000); fds.events = POLLIN; fds.fd = wl_display_get_fd(display); fds.revents = 0; /* This queue is fake to test sub-thread. It will do nothing */ queue = wl_display_create_queue (display); exit_if_fail (queue != NULL); /* sub-thread */ while (1) { while (wl_display_prepare_read_queue (display, queue) != 0) wl_display_dispatch_queue_pending (display, queue); wl_display_flush (display); fprintf (stderr, "*** tid(%ld) sub-poll starts\n", syscall(SYS_gettid)); ret = poll(&fds, 1, -1); fprintf (stderr, "*** tid(%ld) sub-poll returns %d\n", syscall(SYS_gettid), ret); if (ret < 0) { int normal = (errno == EBUSY); wl_display_cancel_read (display); exit_if_fail (normal); continue; } else { /* sub-thread only reads events from display fd */ wl_display_read_events (display); } } } static void thread_start (struct wl_display *display) { pthread_t thread; if(pthread_create (&thread, NULL, thread_sub, display) < 0) { fprintf (stdout, "failed: staring thread\n"); exit (-1); } pthread_detach (thread); } int main(int argc, char *argv[]) { struct wl_display *display; struct pollfd fds; int ret; /* create a display object */ display = wl_display_connect (NULL); exit_if_fail (display != NULL); /* start sub-thread with the same display object */ thread_start (display); fds.events = POLLIN; fds.fd = wl_display_get_fd (display); fds.revents = 0; /* main-thread */ while (1) { struct wl_callback *callback = wl_display_sync (display); exit_if_fail (callback != NULL); wl_callback_add_listener(callback, &sync_listener, NULL); /* "flush -> dispatch_pending -> poll -> dispatch" this is exactly what * weston-client and toolkits do to handle reqeusts and events in client * side. We might can use prepare_read, read_events, and dispatch_pending. * But it creates problem where mesa uses wl_display_dispatch_queue. * A thread would block. */ wl_display_flush (display); wl_display_dispatch_pending (display); fprintf (stdout, "+++ tid(%ld) main-poll starts\n", syscall(SYS_gettid)); ret = poll (&fds, 1, -1); fprintf (stdout, "+++ tid(%ld) main-poll returns %d\n", syscall(SYS_gettid), ret); /* main-thread reads and dispatches events. Between main-thread and * sub-thread, there is competition while reading events from display fd. */ wl_display_dispatch (display); } return 0; }