[PATCH wayland v2] server: document wl_event_loop and wl_event_source

Christopher James Halse Rogers chris at cooperteam.net
Thu Aug 24 23:51:14 UTC 2017


On Fri, 2017-08-18 at 16:09 +0300, Pekka Paalanen wrote:
> From: Pekka Paalanen <pekka.paalanen at collabora.co.uk>
> 
> This documents all the public API related to wl_event_loop and
> wl_event_source objects.
> 
> Signed-off-by: Pekka Paalanen <pekka.paalanen at collabora.co.uk>
> Reviewed-by: Yong Bakos <ybakos at humanoriented.com>
> [Pekka: fixed typos pointed by Yong]
> 
> ---
> 
> v2: Just typo fixes. Anyone else care to read this through?
> 
> If not, I think I'll just push this next week.
> ---
>  doc/doxygen/Makefile.am   |   1 +
>  src/event-loop.c          | 244
> +++++++++++++++++++++++++++++++++++++++++++++-
>  src/wayland-server-core.h |  77 +++++++++++++++
>  3 files changed, 321 insertions(+), 1 deletion(-)
> 
> diff --git a/doc/doxygen/Makefile.am b/doc/doxygen/Makefile.am
> index 276a395..f8b0b3a 100644
> --- a/doc/doxygen/Makefile.am
> +++ b/doc/doxygen/Makefile.am
> @@ -19,6 +19,7 @@ scanned_src_files_Client = 				
> \
>  
>  scanned_src_files_Server = 				\
>  	$(scanned_src_files_shared)			\
> +	$(top_srcdir)/src/event-loop.c		\
>  	$(top_srcdir)/src/wayland-server.c	\
>  	$(top_srcdir)/src/wayland-server.h	\
>  	$(top_srcdir)/src/wayland-server-core.h	\
> diff --git a/src/event-loop.c b/src/event-loop.c
> index 6130d2a..9bc52ac 100644
> --- a/src/event-loop.c
> +++ b/src/event-loop.c
> @@ -42,6 +42,8 @@
>  #include "wayland-server-core.h"
>  #include "wayland-os.h"
>  
> +/** \cond INTERNAL */
> +
>  struct wl_event_loop {
>  	int epoll_fd;
>  	struct wl_list check_list;
> @@ -70,6 +72,8 @@ struct wl_event_source_fd {
>  	int fd;
>  };
>  
> +/** \endcond */
> +
>  static int
>  wl_event_source_fd_dispatch(struct wl_event_source *source,
>  			    struct epoll_event *ep)
> @@ -125,6 +129,30 @@ add_source(struct wl_event_loop *loop,
>  	return source;
>  }
>  
> +/** Create a file descriptor event source
> + *
> + * \param loop The event loop that will process the new source.
> + * \param fd The file descriptor to watch.
> + * \param mask A bitwise-or of which events to watch for: \c
> WL_EVENT_READABLE,
> + * \c WL_EVENT_WRITABLE.
> + * \param func The file descriptor dispatch function.
> + * \param data User data.
> + * \return A new file descriptor event source.
> + *
> + * The given file descriptor is initially watched for the events
> given in
> + * \c mask. This can be changed as needed with
> wl_event_source_fd_update().
> + *
> + * If it is possible that program execution causes the file
> descriptor to be
> + * read while leaving the data in a buffer without actually
> processing it,
> + * it may be necessary to register the file descriptor source to be
> re-checked,
> + * see wl_event_source_check(). This will ensure that the dispatch
> function
> + * gets called even if the file descriptor is not readable or
> writable
> + * anymore. This is especially useful with IPC libraries that
> automatically
> + * buffer incoming data, possibly as a side-effect of other
> operations.
> + *
> + * \sa wl_event_loop_fd_func_t
> + * \memberof wl_event_source
> + */
>  WL_EXPORT struct wl_event_source *
>  wl_event_loop_add_fd(struct wl_event_loop *loop,
>  		     int fd, uint32_t mask,
> @@ -145,6 +173,26 @@ wl_event_loop_add_fd(struct wl_event_loop *loop,
>  	return add_source(loop, &source->base, mask, data);
>  }
>  
> +/** Update a file descriptor source's event mask
> + *
> + * \param source The file descriptor event source to update.
> + * \param mask The new mask, a bitwise-or of: \c WL_EVENT_READABLE,
> + * \c WL_EVENT_WRITABLE.
> + * \return 0 on success, -1 on failure.
> + *
> + * This changes which events, readable and/or writable, cause the
> dispatch
> + * callback to be called on.
> + *
> + * File descriptors are usually writable to begin with, so they do
> not need to
> + * be polled for writable until a write actually fails. When a write
> fails,
> + * the event mask can be changed to poll for readable and writable,
> delivering
> + * a dispatch callback when it is possible to write more. Once all
> data has
> + * been written, the mask can be changed to poll only for readable
> to avoid
> + * busy-looping on dispatch.
> + *
> + * \sa wl_event_loop_add_fd()
> + * \memberof wl_event_source
> + */
>  WL_EXPORT int
>  wl_event_source_fd_update(struct wl_event_source *source, uint32_t
> mask)
>  {
> @@ -161,11 +209,15 @@ wl_event_source_fd_update(struct
> wl_event_source *source, uint32_t mask)
>  	return epoll_ctl(loop->epoll_fd, EPOLL_CTL_MOD, source->fd,
> &ep);
>  }
>  
> +/** \cond INTERNAL */
> +
>  struct wl_event_source_timer {
>  	struct wl_event_source base;
>  	wl_event_loop_timer_func_t func;
>  };
>  
> +/** \endcond */
> +
>  static int
>  wl_event_source_timer_dispatch(struct wl_event_source *source,
>  			       struct epoll_event *ep)
> @@ -187,6 +239,19 @@ struct wl_event_source_interface
> timer_source_interface = {
>  	wl_event_source_timer_dispatch,
>  };
>  
> +/** Create a timer event source
> + *
> + * \param loop The event loop that will process the new source.
> + * \param func The timer dispatch function.
> + * \param data User data.
> + * \return A new timer event source.
> + *
> + * The timer is initially disarmed. It needs to be armed with a call
> to
> + * wl_event_source_timer_update() before it can trigger a dispatch
> call.
> + *
> + * \sa wl_event_loop_timer_func_t
> + * \memberof wl_event_source
> + */
>  WL_EXPORT struct wl_event_source *
>  wl_event_loop_add_timer(struct wl_event_loop *loop,
>  			wl_event_loop_timer_func_t func,
> @@ -206,6 +271,22 @@ wl_event_loop_add_timer(struct wl_event_loop
> *loop,
>  	return add_source(loop, &source->base, WL_EVENT_READABLE,
> data);
>  }
>  
> +/** Arm or disarm a timer
> + *
> + * \param source The timer event source to modify.
> + * \param ms_delay The timeout in milliseconds.
> + * \return 0 on success, -1 on failure.
> + *
> + * If the timeout is zero, the timer is disarmed.
> + *
> + * If the timeout is non-zero, the timer is set to expire after the
> given
> + * timeout in milliseconds. When the timer expires, the dispatch
> function
> + * set with wl_event_loop_add_timer() is called once from
> + * wl_event_loop_dispatch(). If another dispatch is desired after
> another
> + * expiry, wm_event_source_timer_update() needs to be called again.

Typo, wl_event_source_timer_update()

> + *
> + * \memberof wl_event_source
> + */
>  WL_EXPORT int
>  wl_event_source_timer_update(struct wl_event_source *source, int
> ms_delay)
>  {
> @@ -221,12 +302,16 @@ wl_event_source_timer_update(struct
> wl_event_source *source, int ms_delay)
>  	return 0;
>  }
>  
> +/** \cond INTERNAL */
> +
>  struct wl_event_source_signal {
>  	struct wl_event_source base;
>  	int signal_number;
>  	wl_event_loop_signal_func_t func;
>  };
>  
> +/** \endcond */
> +
>  static int
>  wl_event_source_signal_dispatch(struct wl_event_source *source,
>  				struct epoll_event *ep)
> @@ -249,6 +334,25 @@ struct wl_event_source_interface
> signal_source_interface = {
>  	wl_event_source_signal_dispatch,
>  };
>  
> +/** Create a POSIX signal event source
> + *
> + * \param loop The event loop that will process the new source.
> + * \param signal_number Number of the signal to watch for.
> + * \param func The signal dispatch function.
> + * \param data User data.
> + * \return A new signal event source.
> + *
> + * This function blocks the normal delivery of the given signal in
> the calling
> + * thread, and creates a "watch" for it. Signal delivery no longer
> happens
> + * asynchronously, but by wl_event_loop_dispatch() calling the
> dispatch
> + * callback function \c func.
> + *
> + * It is the caller's responsibility to ensure that all other
> threads have
> + * also blocked the signal.
> + *
> + * \sa wl_event_loop_signal_func_t
> + * \memberof wl_event_source
> + */
>  WL_EXPORT struct wl_event_source *
>  wl_event_loop_add_signal(struct wl_event_loop *loop,
>  			 int signal_number,
> @@ -275,15 +379,39 @@ wl_event_loop_add_signal(struct wl_event_loop
> *loop,
>  	return add_source(loop, &source->base, WL_EVENT_READABLE,
> data);
>  }
>  
> +/** \cond INTERNAL */
> +
>  struct wl_event_source_idle {
>  	struct wl_event_source base;
>  	wl_event_loop_idle_func_t func;
>  };
>  
> +/** \endcond */
> +
>  struct wl_event_source_interface idle_source_interface = {
>  	NULL,
>  };
>  
> +/** Create an idle task
> + *
> + * \param loop The event loop that will process the new task.
> + * \param func The idle task dispatch function.
> + * \param data User data.
> + * \return A new idle task (an event source).
> + *
> + * Idle tasks are dispatched before wl_event_loop_dispatch() goes to
> sleep.
> + * See wl_event_loop_dispatch() for more details.
> + *
> + * Idle tasks fire once, and are automatically destroyed right after
> the
> + * callback function has been called.
> + *
> + * An idle task can be cancelled before the callback has been called
> by
> + * wl_event_source_remove(). Calling wl_event_source_remove() after
> or from
> + * within the callback results in undefined behaviour.
> + *
> + * \sa wl_event_loop_idle_func_t
> + * \memberof wl_event_source
> + */
>  WL_EXPORT struct wl_event_source *
>  wl_event_loop_add_idle(struct wl_event_loop *loop,
>  		       wl_event_loop_idle_func_t func,
> @@ -307,12 +435,40 @@ wl_event_loop_add_idle(struct wl_event_loop
> *loop,
>  	return &source->base;
>  }
>  
> +/** Mark event source to be re-checked
> + *
> + * \param source The event source to be re-checked.
> + *
> + * This function permanently marks the event source to be re-checked 
> after
> + * the normal dispatch of sources in wl_event_loop_dispatch(). Re-
> checking
> + * will keep iterating over all such event sources until the
> dispatch
> + * function for them all returns zero.
> + *
> + * Re-checking is used on sources that may become ready to dispatch
> as a
> + * side-effect of dispatching themselves or other event sources,
> including idle
> + * sources. Re-checking ensures all the incoming events have been
> fully drained
> + * before wl_event_loop_dispatch() returns.
> + *
> + * \memberof wl_event_source
> + */
>  WL_EXPORT void
>  wl_event_source_check(struct wl_event_source *source)
>  {
>  	wl_list_insert(source->loop->check_list.prev, &source-
> >link);
>  }
>  
> +/** Remove an event source from its event loop
> + *
> + * \param source The event source to be removed.
> + * \return Zero.
> + *
> + * The event source is removed from the event loop it was created
> for,
> + * and is effectively destroyed. This invalidates \c source .
> + * The dispatch function of the source will no longer be called
> through this
> + * source.
> + *
> + * \memberof wl_event_source
> + */
>  WL_EXPORT int
>  wl_event_source_remove(struct wl_event_source *source)
>  {
> @@ -343,6 +499,20 @@ wl_event_loop_process_destroy_list(struct
> wl_event_loop *loop)
>  	wl_list_init(&loop->destroy_list);
>  }
>  
> +/** Create a new event loop context
> + *
> + * \return A new event loop context object.
> + *
> + * This creates a new event loop context. Initially this context is
> empty.
> + * Event sources need to be explicitly added to it.
> + *
> + * Normally the event loop is run by calling
> wl_event_loop_dispatch() in
> + * a loop until the program terminates. Alternatively, an event loop
> can be
> + * embedded in another event loop by its file descriptor, see
> + * wl_event_loop_get_fd().
> + *
> + * \memberof wl_event_loop
> + */
>  WL_EXPORT struct wl_event_loop *
>  wl_event_loop_create(void)
>  {
> @@ -366,6 +536,19 @@ wl_event_loop_create(void)
>  	return loop;
>  }
>  
> +/** Destroy an event loop context
> + *
> + * \param loop The event loop to be destroyed.
> + *
> + * This emits the event loop destroy signal, closes the event loop
> file
> + * descriptor, and frees \c loop.
> + *
> + * If the event loop has existing sources, those cannot be safely
> removed
> + * afterwards. Therefore one must call wl_event_source_remove() on
> all
> + * event sources before destroying the event loop context.
> + *
> + * \memberof wl_event_loop
> + */
>  WL_EXPORT void
>  wl_event_loop_destroy(struct wl_event_loop *loop)
>  {
> @@ -391,6 +574,13 @@ post_dispatch_check(struct wl_event_loop *loop)
>  	return n;
>  }
>  
> +/** Dispatch the idle sources
> + *
> + * \param loop The event loop whose idle sources are dispatched.
> + *
> + * \sa wl_event_loop_add_idle()
> + * \memberof wl_event_loop
> + */
>  WL_EXPORT void
>  wl_event_loop_dispatch_idle(struct wl_event_loop *loop)
>  {
> @@ -404,6 +594,26 @@ wl_event_loop_dispatch_idle(struct wl_event_loop
> *loop)
>  	}
>  }
>  
> +/** Wait for events and dispatch them
> + *
> + * \param loop The event loop whose sources to wait for.
> + * \param timeout The polling timeout in milliseconds.
> + * \return 0 for success, -1 for polling error.
> + *
> + * All the associated event sources are polled. This function blocks
> until
> + * any event source delivers an event (idle sources excluded), or
> the timeout
> + * expires. A timeout of -1 disables the timeout, causing the
> function to block
> + * indefinitely. A timeout of zero causes the poll to always return
> immediately.
> + *
> + * All idle sources are dispatched before blocking. An idle source
> is destroyed
> + * when it is dispatched. After blocking, all other ready sources
> are
> + * dispatched. Then, idle sources are dispatched again, in case the
> dispatched
> + * events created idle sources. Finally, all sources marked with
> + * wl_event_source_check() are dispatched in a loop until their
> dispatch
> + * functions all return zero.
> + *
> + * \memberof wl_event_loop
> + */
>  WL_EXPORT int
>  wl_event_loop_dispatch(struct wl_event_loop *loop, int timeout)
>  {
> @@ -434,12 +644,36 @@ wl_event_loop_dispatch(struct wl_event_loop
> *loop, int timeout)
>  	return 0;
>  }
>  
> +/** Get the event loop file descriptor
> + *
> + * \param loop The event loop context.
> + * \return The aggregate file descriptor.
> + *
> + * This function returns the aggregate file descriptor, that
> represents all
> + * the event sources (idle sources excluded) associated with the
> given event
> + * loop context. When any event source makes an event available, it
> will be
> + * reflected in the aggregate file descriptor.
> + *
> + * When the aggregate file descriptor delivers an event, one can
> call
> + * wl_event_loop_dispatch() on the event loop context to dispatch
> all the
> + * available events.
> + *
> + * \memberof wl_event_loop
> + */
>  WL_EXPORT int
>  wl_event_loop_get_fd(struct wl_event_loop *loop)
>  {
>  	return loop->epoll_fd;
>  }
>  
> +/** Register a destroy listener for an event loop context
> + *
> + * \param loop The event loop context whose destruction to listen
> for.
> + * \param listener The listener with the callback to be called.
> + *
> + * \sa wl_listener
> + * \memberof wl_event_loop
> + */
>  WL_EXPORT void
>  wl_event_loop_add_destroy_listener(struct wl_event_loop *loop,
>  				   struct wl_listener *listener)
> @@ -447,10 +681,18 @@ wl_event_loop_add_destroy_listener(struct
> wl_event_loop *loop,
>  	wl_signal_add(&loop->destroy_signal, listener);
>  }
>  
> +/** Get the listener struct for the specified callback
> + *
> + * \param loop The event loop context to inspect.
> + * \param notify The destroy callback to find.
> + * \return The wl_listener registered to the event loop context with
> + * the give callback pointer.

Typo: given

> + *
> + * \memberof wl_event_loop
> + */
>  WL_EXPORT struct wl_listener *
>  wl_event_loop_get_destroy_listener(struct wl_event_loop *loop,
>  				   wl_notify_func_t notify)
>  {
>  	return wl_signal_get(&loop->destroy_signal, notify);
>  }
> -
> diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h
> index 61da8ab..fd458c5 100644
> --- a/src/wayland-server-core.h
> +++ b/src/wayland-server-core.h
> @@ -43,11 +43,88 @@ enum {
>  	WL_EVENT_ERROR    = 0x08
>  };
>  
> +/** File descriptor dispatch function type
> + *
> + * Functions of this type are used as callbacks for file descriptor
> events.
> + *
> + * \param fd The file descriptor delivering the event.
> + * \param mask Describes the kind of the event as a bitwise-or of:
> + * \c WL_EVENT_READABLE, \c WL_EVENT_WRITABLE, \c WL_EVENT_HANGUP,
> + * \c WL_EVENT_ERROR.
> + * \param data The user data argument of the related
> wl_event_loop_add_fd()
> + * call.
> + * \return If the event source is registered for re-check with
> + * wl_event_source_check(): 0 for all done, 1 for needing a re-
> check.
> + * If not registered, the return value is ignored and should be
> zero.
> + *
> + * \sa wl_event_loop_add_fd()
> + * \memberof wl_event_source
> + */
>  typedef int (*wl_event_loop_fd_func_t)(int fd, uint32_t mask, void
> *data);
> +
> +/** Timer dispatch function type
> + *
> + * Functions of this type are used as callbacks for timer expiry.
> + *
> + * \param data The user data argument of the related
> wl_event_loop_add_timer()
> + * call.
> + * \return If the event source is registered for re-check with
> + * wl_event_source_check(): 0 for all done, 1 for needing a re-
> check.
> + * If not registered, the return value is ignored and should be
> zero.
> + *
> + * \sa wl_event_loop_add_timer()
> + * \memberof wl_event_source
> + */
>  typedef int (*wl_event_loop_timer_func_t)(void *data);
> +
> +/** Signal dispatch function type
> + *
> + * Functions of this type are used as callbacks for (POSIX) signals.
> + *
> + * \param signal_number
> + * \param data The user data argument of the related
> wl_event_loop_add_signal()
> + * call.
> + * \return If the event source is registered for re-check with
> + * wl_event_source_check(): 0 for all done, 1 for needing a re-
> check.
> + * If not registered, the return value is ignored and should be
> zero.
> + *
> + * \sa wl_event_loop_add_signal()
> + * \memberof wl_event_source
> + */
>  typedef int (*wl_event_loop_signal_func_t)(int signal_number, void
> *data);
> +
> +/** Idle task function type
> + *
> + * Functions of this type are used as callbacks before blocking in
> + * wl_event_loop_dispatch().
> + *
> + * \param data The user data argument of the related
> wl_event_loop_add_idle()
> + * call.
> + *
> + * \sa wl_event_loop_add_idle() wl_event_loop_dispatch()
> + * \memberof wl_event_source
> + */
>  typedef void (*wl_event_loop_idle_func_t)(void *data);
>  
> +/** \struct wl_event_loop
> + *
> + * \brief An event loop context
> + *
> + * Usually you create an event loop context, add sources to it, and
> call
> + * wl_event_loop_dispatch() in a loop to process events.
> + *
> + * \sa wl_event_source
> + */
> +
> +/** \struct wl_event_source
> + *
> + * \brief An abstract event source
> + *
> + * This is the generic type for fd, timer, signal, and idle sources.
> + * Functions that operate on specific source types must not be used
> with
> + * a different type, even if the function signature allows it.
> + */
> +
>  struct wl_event_loop *
>  wl_event_loop_create(void);
>  

How convenient that we both independently happened to look at
documenting this :).

With the exception of the two typos,

Reviewed-By: Christopher James Halse Rogers
<christopher.halse.rogers at canonical.com>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: This is a digitally signed message part
URL: <https://lists.freedesktop.org/archives/wayland-devel/attachments/20170825/15b3a3e6/attachment-0001.sig>


More information about the wayland-devel mailing list