wayland中有幾個概念不太好理解,主要是圍繞着wl_display_dispatch容易產生很多問題 。翻了翻源碼,發現dispatch等函數基本上都是圍繞着
struct wl_event_queue來進行的。
在最早的wl_display_connect中,調用了wl_display_connect_fd;

對應了struct wl_display的兩個queue;

對於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 的配合下,可以實現線程安全,即使在多線程中,也不會因為多次調用這個函數而出現問題
