walyand学习笔记(九) wl_dispaly_dispatch线程安全分析

wayland中有几个概念不太好理解,主要是围绕着wl_display_dispatch容易产生很多问题 。翻了翻源码,发现dispatch等函数基本上都是围绕着

struct wl_event_queue来进行的。

 在最早的wl_display_connect中,调用了wl_display_connect_fd;

walyand学习笔记(九) wl_dispaly_dispatch线程安全分析

 

 对应了struct wl_display的两个queue;

walyand学习笔记(九) wl_dispaly_dispatch线程安全分析

 

 对于wl_display_dispatch

WL_EXPORT int
wl_display_dispatch(struct wl_display *display)
{
    return wl_display_dispatch_queue(display, &display->default_queue);
}

然后就进入了本文的核心内容,分析一下wl_display_dispatch_queue,先贴上源码:

WL_EXPORT int
wl_display_dispatch_queue(struct wl_display *display,
              struct wl_event_queue *queue)
{
    int ret;

    if (wl_display_prepare_read_queue(display, queue) == -1)
        return wl_display_dispatch_queue_pending(display, queue);

    while (true) {
        ret = wl_display_flush(display);

        if (ret != -1 || errno != EAGAIN)
            break;

        if (wl_display_poll(display, POLLOUT) == -1) {
            wl_display_cancel_read(display);
            return -1;
        }
    }

    /* Don't stop if flushing hits an EPIPE; continue so we can read any
     * protocol error that may have triggered it. */
    if (ret < 0 && errno != EPIPE) {
        wl_display_cancel_read(display);
        return -1;
    }

    if (wl_display_poll(display, POLLIN) == -1) {
        wl_display_cancel_read(display);
        return -1;
    }

    if (wl_display_read_events(display) == -1)
        return -1;

    return wl_display_dispatch_queue_pending(display, queue);
}

 

结合下面的表格来理解这块函数的真正用意:

函数名 作用 注解
wl_display_dispatch 在display的default queue上,读取server的event,如果没有 event会阻塞在此处,直到收到event为止  线程安全
wl_display_dispatch_queue  同上,不过是可以指定一个新的event queue,而非在default queue上  
wl_display_dispatch_queue_pending  把当前pending在in queue(ring buffer)中的events 处理掉,并返回dispatch的event个数

如果没有pending的events, 会立即返回

wl_display_flush  将当前pending在out queue中的cmds全部发送给server  
wl_display_roundtrip_queue  通过wl_display_sync,告知server端,处理完所有request后,通知到client的回调,这个回调是定义在wayland-client.c中的sync_listener, server在sync ack后,这个函数才会返回  
wl_display_roundtrip  同上,只是在display的default queue上dispatch和等待ack  
wl_display_prepare_read_queue  判断指定的event queue中是否是empty,若是返回0,同时使内部的reader_counter++,否则返回-1并且设置errno为EAGAIN  
wl_display_prepare_read  同上,只是在default queue上去prepare_read_queue  
wl_display_cancel_read  会使display结构体内部维护的一个引用计数reader_counter--  
wl_display_read_events

 需要在prepare_read返回0后使用,该函数会使内部的reader_counter--,当某个线程调用该函数后,使reader_counter减为0,则触发真正的从缓冲区中读取数据,并唤醒其它阻塞在condition_wait的线程;

其它调用该函数但是没有使reader_counter减为0的调用者将进入condition_wait的状态,等待被某个wl_display_read_events或者wl_display_cancel_read来唤醒

 
     

 

 综合下来,我的理解就是:

wl_display_dispatch在wl_prepare_read 和 poll 以及 wl_display_read_events 的配合下,可以实现线程安全,即使在多线程中,也不会因为多次调用这个函数而出现问题

 

上一篇:R语言图像处理EBImage包详解


下一篇:H5+CSS3 web前端入门-导读