libpulse_binding/mainloop/
mod.rs

1// Copyright 2017 Lyndon Brown
2//
3// This file is part of the PulseAudio Rust language binding.
4//
5// Licensed under the MIT license or the Apache license (version 2.0), at your option. You may not
6// copy, modify, or distribute this file except in compliance with said license. You can find copies
7// of these licenses either in the LICENSE-MIT and LICENSE-APACHE files, or alternatively at
8// <http://opensource.org/licenses/MIT> and <http://www.apache.org/licenses/LICENSE-2.0>
9// respectively.
10//
11// Portions of documentation are copied from the LGPL 2.1+ licensed PulseAudio C headers on a
12// fair-use basis, as discussed in the overall project readme (available in the git repository).
13
14//! Main loop abstraction layer.
15//!
16//! # Main Loop Abstraction
17//!
18//! Both the PulseAudio core and the PulseAudio client library use a main loop abstraction layer.
19//! Due to this it is possible to embed PulseAudio into other applications easily.
20//!
21//! This abstraction contains three basic elements:
22//!
23//! * Deferred events: Events that will trigger as soon as possible. Note that some implementations
24//!   may block all other events when a deferred event is active.
25//! * I/O events: Events that trigger on file descriptor activities.
26//! * Timer events: Events that trigger after a fixed amount of time.
27//!
28//! The abstraction is represented as a number of function pointers in the
29//! [`MainloopApi`](self::api::MainloopApi) structure.
30//!
31//! To actually be able to use these functions, an implementation needs to be coupled to the
32//! abstraction. There are three of these shipped with PulseAudio, but any other can be used with a
33//! minimal amount of work, provided it supports the three basic events listed above.
34//!
35//! The implementations shipped with PulseAudio are:
36//!
37//! * [Standard](mod@standard): A minimal but fast implementation based on the C library’s poll()
38//!   function.
39//! * [Threaded](mod@threaded): A special version of the previous implementation where all of
40//!   PulseAudio’s internal handling runs in a separate thread.
41//! * ‘Glib’: A wrapper around GLib’s main loop. This is provided in the separate
42//!   `libpulse_glib_binding` crate.
43//!
44//! UNIX signals may be hooked to a main loop using the functionality from the
45//! [`signal`](mod@signal) mod. This relies only on the main loop abstraction and can therefore be
46//! used with any of the implementations.
47//!
48//! # Callback Notes
49//!
50//! ## Execution
51//!
52//! As described in the [standard mainloop] documentation], there are three phases to mainloop
53//! execution, and the third - ‘dispatch’ - is when user callbacks get executed.
54//!
55//! It is important to understand that while it is *typical* that user callbacks are executed
56//! by the mainloop’s dispatcher, callback execution is not exclusively done there; in some cases
57//! callbacks get executed directly in synchronous function execution. For instance, if you set up
58//! a context state change callback, then try to connect the context object, execution of the
59//! ‘connect’ function call involves (internally within the PulseAudio client library) direct
60//! execution of this callback in setting the initial connection state. After returning, the
61//! callback is then on only executed asynchronously from the mainloop’s dispatcher.
62//!
63//! While execution using the [standard mainloop] is entirely synchronous, the [threaded mainloop]
64//! implementation runs the standard mainloop in a separate thread and callback execution occurs
65//! asynchronously, requiring careful use of the mainloop’s [`lock()`] method. When writing
66//! callbacks with the threaded mainloop, users must beware the potential that in a few cases the
67//! callback may be executed in two different scenarios, and with different threads. Note that the
68//! threaded mainloop has an [`in_thread()`] method for determining whether or not the thread it is
69//! executed from is the special event loop thread.
70//!
71//! ## Queued Events and Changing Callbacks
72//!
73//! It is also worth understanding that any events that get queued for dispatch do **not** hold
74//! cached copies of user callback parameters. Where applicable, you can thus freely and safely
75//! change the set callback, with that change taking effect immediately to all future event
76//! dispatching.
77//!
78//! ## Threading and `Rc`
79//!
80//! Normally when holding multiple references to objects across threads in Rust you would use an
81//! [`Arc`] wrapper. However, with the [threaded mainloop], you may be able to get away with using
82//! just an `Rc` wrapper. Remember that with the [threaded mainloop] you **must** use its
83//! [`lock()`] method to synchronise access to objects, and so you know that at any one moment
84//! either your thread (when you take the lock) **or** the event loop thread hold the lock, never
85//! both, and thus only one thread is ever working with objects at any one time, and since Rust
86//! actually has no idea that more than one thread is involved (hidden in the C library’s
87//! implementation), you can safely get away with using `Rc`.
88//!
89//! [standard mainloop]: mod@standard
90//! [threaded mainloop]: mod@self::threaded
91//! [`lock()`]: self::threaded::Mainloop::lock
92//! [`in_thread()`]: self::threaded::Mainloop::in_thread
93//! [`Arc`]: std::sync::Arc
94
95pub mod api;
96pub mod events;
97pub mod signal;
98pub mod standard;
99pub mod threaded;