153a5a1b3Sopenharmony_ci#ifndef foothreadmainloophfoo
253a5a1b3Sopenharmony_ci#define foothreadmainloophfoo
353a5a1b3Sopenharmony_ci
453a5a1b3Sopenharmony_ci/***
553a5a1b3Sopenharmony_ci  This file is part of PulseAudio.
653a5a1b3Sopenharmony_ci
753a5a1b3Sopenharmony_ci  Copyright 2006 Lennart Poettering
853a5a1b3Sopenharmony_ci  Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
953a5a1b3Sopenharmony_ci
1053a5a1b3Sopenharmony_ci  PulseAudio is free software; you can redistribute it and/or modify
1153a5a1b3Sopenharmony_ci  it under the terms of the GNU Lesser General Public License as published
1253a5a1b3Sopenharmony_ci  by the Free Software Foundation; either version 2.1 of the License,
1353a5a1b3Sopenharmony_ci  or (at your option) any later version.
1453a5a1b3Sopenharmony_ci
1553a5a1b3Sopenharmony_ci  PulseAudio is distributed in the hope that it will be useful, but
1653a5a1b3Sopenharmony_ci  WITHOUT ANY WARRANTY; without even the implied warranty of
1753a5a1b3Sopenharmony_ci  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1853a5a1b3Sopenharmony_ci  General Public License for more details.
1953a5a1b3Sopenharmony_ci
2053a5a1b3Sopenharmony_ci  You should have received a copy of the GNU Lesser General Public License
2153a5a1b3Sopenharmony_ci  along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
2253a5a1b3Sopenharmony_ci***/
2353a5a1b3Sopenharmony_ci
2453a5a1b3Sopenharmony_ci#include <pulse/mainloop-api.h>
2553a5a1b3Sopenharmony_ci#include <pulse/cdecl.h>
2653a5a1b3Sopenharmony_ci#include <pulse/version.h>
2753a5a1b3Sopenharmony_ci
2853a5a1b3Sopenharmony_ciPA_C_DECL_BEGIN
2953a5a1b3Sopenharmony_ci
3053a5a1b3Sopenharmony_ci/** \page threaded_mainloop Threaded Main Loop
3153a5a1b3Sopenharmony_ci *
3253a5a1b3Sopenharmony_ci * \section overv_sec Overview
3353a5a1b3Sopenharmony_ci *
3453a5a1b3Sopenharmony_ci * The threaded main loop implementation is a special version of the primary
3553a5a1b3Sopenharmony_ci * main loop implementation (see \ref mainloop). For the basic design, see
3653a5a1b3Sopenharmony_ci * its documentation.
3753a5a1b3Sopenharmony_ci *
3853a5a1b3Sopenharmony_ci * The added feature in the threaded main loop is that it spawns a new thread
3953a5a1b3Sopenharmony_ci * that runs the real main loop. This allows a synchronous application to use
4053a5a1b3Sopenharmony_ci * the asynchronous API without risking stalling the PulseAudio library.
4153a5a1b3Sopenharmony_ci *
4253a5a1b3Sopenharmony_ci * \section creat_sec Creation
4353a5a1b3Sopenharmony_ci *
4453a5a1b3Sopenharmony_ci * A pa_threaded_mainloop object is created using pa_threaded_mainloop_new().
4553a5a1b3Sopenharmony_ci * This will only allocate the required structures though, so to use it the
4653a5a1b3Sopenharmony_ci * thread must also be started. This is done through
4753a5a1b3Sopenharmony_ci * pa_threaded_mainloop_start(), after which you can start using the main loop.
4853a5a1b3Sopenharmony_ci *
4953a5a1b3Sopenharmony_ci * \section destr_sec Destruction
5053a5a1b3Sopenharmony_ci *
5153a5a1b3Sopenharmony_ci * When the PulseAudio connection has been terminated, the thread must be
5253a5a1b3Sopenharmony_ci * stopped and the resources freed. Stopping the thread is done using
5353a5a1b3Sopenharmony_ci * pa_threaded_mainloop_stop(), which must be called without the lock (see
5453a5a1b3Sopenharmony_ci * below) held. When that function returns, the thread is stopped and the
5553a5a1b3Sopenharmony_ci * pa_threaded_mainloop object can be freed using pa_threaded_mainloop_free().
5653a5a1b3Sopenharmony_ci *
5753a5a1b3Sopenharmony_ci * \section lock_sec Locking
5853a5a1b3Sopenharmony_ci *
5953a5a1b3Sopenharmony_ci * Since the PulseAudio API doesn't allow concurrent accesses to objects,
6053a5a1b3Sopenharmony_ci * a locking scheme must be used to guarantee safe usage. The threaded main
6153a5a1b3Sopenharmony_ci * loop API provides such a scheme through the functions
6253a5a1b3Sopenharmony_ci * pa_threaded_mainloop_lock() and pa_threaded_mainloop_unlock().
6353a5a1b3Sopenharmony_ci *
6453a5a1b3Sopenharmony_ci * The lock is recursive, so it's safe to use it multiple times from the same
6553a5a1b3Sopenharmony_ci * thread. Just make sure you call pa_threaded_mainloop_unlock() the same
6653a5a1b3Sopenharmony_ci * number of times you called pa_threaded_mainloop_lock().
6753a5a1b3Sopenharmony_ci *
6853a5a1b3Sopenharmony_ci * The lock needs to be held whenever you call any PulseAudio function that
6953a5a1b3Sopenharmony_ci * uses an object associated with this main loop. Those objects include
7053a5a1b3Sopenharmony_ci * pa_mainloop, pa_context, pa_stream and pa_operation, and the various event
7153a5a1b3Sopenharmony_ci * objects (pa_io_event, pa_time_event, pa_defer_event). Make sure you do not
7253a5a1b3Sopenharmony_ci * hold on to the lock more than necessary though, as the threaded main loop
7353a5a1b3Sopenharmony_ci * stops while the lock is held.
7453a5a1b3Sopenharmony_ci *
7553a5a1b3Sopenharmony_ci * Example:
7653a5a1b3Sopenharmony_ci *
7753a5a1b3Sopenharmony_ci * \code
7853a5a1b3Sopenharmony_ci * void my_check_stream_func(pa_threaded_mainloop *m, pa_stream *s) {
7953a5a1b3Sopenharmony_ci *     pa_stream_state_t state;
8053a5a1b3Sopenharmony_ci *
8153a5a1b3Sopenharmony_ci *     pa_threaded_mainloop_lock(m);
8253a5a1b3Sopenharmony_ci *
8353a5a1b3Sopenharmony_ci *     state = pa_stream_get_state(s);
8453a5a1b3Sopenharmony_ci *
8553a5a1b3Sopenharmony_ci *     pa_threaded_mainloop_unlock(m);
8653a5a1b3Sopenharmony_ci *
8753a5a1b3Sopenharmony_ci *     if (state == PA_STREAM_READY)
8853a5a1b3Sopenharmony_ci *         printf("Stream is ready!");
8953a5a1b3Sopenharmony_ci *     else
9053a5a1b3Sopenharmony_ci *         printf("Stream is not ready!");
9153a5a1b3Sopenharmony_ci * }
9253a5a1b3Sopenharmony_ci * \endcode
9353a5a1b3Sopenharmony_ci *
9453a5a1b3Sopenharmony_ci * \section cb_sec Callbacks
9553a5a1b3Sopenharmony_ci *
9653a5a1b3Sopenharmony_ci * Callbacks in PulseAudio are asynchronous, so they require extra care when
9753a5a1b3Sopenharmony_ci * using them together with a threaded main loop.
9853a5a1b3Sopenharmony_ci *
9953a5a1b3Sopenharmony_ci * The easiest way to turn the callback based operations into synchronous
10053a5a1b3Sopenharmony_ci * ones, is to simply wait for the callback to be called and continue from
10153a5a1b3Sopenharmony_ci * there. This is the approach chosen in PulseAudio's threaded API.
10253a5a1b3Sopenharmony_ci *
10353a5a1b3Sopenharmony_ci * \subsection basic_subsec Basic callbacks
10453a5a1b3Sopenharmony_ci *
10553a5a1b3Sopenharmony_ci * For the basic case, where all that is required is to wait for the callback
10653a5a1b3Sopenharmony_ci * to be invoked, the code should look something like this:
10753a5a1b3Sopenharmony_ci *
10853a5a1b3Sopenharmony_ci * Example:
10953a5a1b3Sopenharmony_ci *
11053a5a1b3Sopenharmony_ci * \code
11153a5a1b3Sopenharmony_ci * static void my_drain_callback(pa_stream *s, int success, void *userdata) {
11253a5a1b3Sopenharmony_ci *     pa_threaded_mainloop *m;
11353a5a1b3Sopenharmony_ci *
11453a5a1b3Sopenharmony_ci *     m = userdata;
11553a5a1b3Sopenharmony_ci *     assert(m);
11653a5a1b3Sopenharmony_ci *
11753a5a1b3Sopenharmony_ci *     pa_threaded_mainloop_signal(m, 0);
11853a5a1b3Sopenharmony_ci * }
11953a5a1b3Sopenharmony_ci *
12053a5a1b3Sopenharmony_ci * void my_drain_stream_func(pa_threaded_mainloop *m, pa_stream *s) {
12153a5a1b3Sopenharmony_ci *     pa_operation *o;
12253a5a1b3Sopenharmony_ci *
12353a5a1b3Sopenharmony_ci *     pa_threaded_mainloop_lock(m);
12453a5a1b3Sopenharmony_ci *
12553a5a1b3Sopenharmony_ci *     o = pa_stream_drain(s, my_drain_callback, m);
12653a5a1b3Sopenharmony_ci *     assert(o);
12753a5a1b3Sopenharmony_ci *
12853a5a1b3Sopenharmony_ci *     while (pa_operation_get_state(o) == PA_OPERATION_RUNNING)
12953a5a1b3Sopenharmony_ci *         pa_threaded_mainloop_wait(m);
13053a5a1b3Sopenharmony_ci *
13153a5a1b3Sopenharmony_ci *     pa_operation_unref(o);
13253a5a1b3Sopenharmony_ci *
13353a5a1b3Sopenharmony_ci *     pa_threaded_mainloop_unlock(m);
13453a5a1b3Sopenharmony_ci * }
13553a5a1b3Sopenharmony_ci * \endcode
13653a5a1b3Sopenharmony_ci *
13753a5a1b3Sopenharmony_ci * The main function, my_drain_stream_func(), will wait for the callback to
13853a5a1b3Sopenharmony_ci * be called using pa_threaded_mainloop_wait().
13953a5a1b3Sopenharmony_ci *
14053a5a1b3Sopenharmony_ci * If your application is multi-threaded, then this waiting must be
14153a5a1b3Sopenharmony_ci * done inside a while loop. The reason for this is that multiple
14253a5a1b3Sopenharmony_ci * threads might be using pa_threaded_mainloop_wait() at the same
14353a5a1b3Sopenharmony_ci * time. Each thread must therefore verify that it was its callback
14453a5a1b3Sopenharmony_ci * that was invoked. Also the underlying OS synchronization primitives
14553a5a1b3Sopenharmony_ci * are usually not free of spurious wake-ups, so a
14653a5a1b3Sopenharmony_ci * pa_threaded_mainloop_wait() must be called within a loop even if
14753a5a1b3Sopenharmony_ci * you have only one thread waiting.
14853a5a1b3Sopenharmony_ci *
14953a5a1b3Sopenharmony_ci * The callback, my_drain_callback(), indicates to the main function that it
15053a5a1b3Sopenharmony_ci * has been called using pa_threaded_mainloop_signal().
15153a5a1b3Sopenharmony_ci *
15253a5a1b3Sopenharmony_ci * As you can see, pa_threaded_mainloop_wait() may only be called with
15353a5a1b3Sopenharmony_ci * the lock held. The same thing is true for pa_threaded_mainloop_signal(),
15453a5a1b3Sopenharmony_ci * but as the lock is held before the callback is invoked, you do not have to
15553a5a1b3Sopenharmony_ci * deal with that.
15653a5a1b3Sopenharmony_ci *
15753a5a1b3Sopenharmony_ci * The functions will not dead lock because the wait function will release
15853a5a1b3Sopenharmony_ci * the lock before waiting and then regrab it once it has been signalled.
15953a5a1b3Sopenharmony_ci * For those of you familiar with threads, the behaviour is that of a
16053a5a1b3Sopenharmony_ci * condition variable.
16153a5a1b3Sopenharmony_ci *
16253a5a1b3Sopenharmony_ci * \subsection data_subsec Data callbacks
16353a5a1b3Sopenharmony_ci *
16453a5a1b3Sopenharmony_ci * For many callbacks, simply knowing that they have been called is
16553a5a1b3Sopenharmony_ci * insufficient. The callback also receives some data that is desired. To
16653a5a1b3Sopenharmony_ci * access this data safely, we must extend our example a bit:
16753a5a1b3Sopenharmony_ci *
16853a5a1b3Sopenharmony_ci * \code
16953a5a1b3Sopenharmony_ci * static int * volatile drain_result = NULL;
17053a5a1b3Sopenharmony_ci *
17153a5a1b3Sopenharmony_ci * static void my_drain_callback(pa_stream*s, int success, void *userdata) {
17253a5a1b3Sopenharmony_ci *     pa_threaded_mainloop *m;
17353a5a1b3Sopenharmony_ci *
17453a5a1b3Sopenharmony_ci *     m = userdata;
17553a5a1b3Sopenharmony_ci *     assert(m);
17653a5a1b3Sopenharmony_ci *
17753a5a1b3Sopenharmony_ci *     drain_result = &success;
17853a5a1b3Sopenharmony_ci *
17953a5a1b3Sopenharmony_ci *     pa_threaded_mainloop_signal(m, 1);
18053a5a1b3Sopenharmony_ci * }
18153a5a1b3Sopenharmony_ci *
18253a5a1b3Sopenharmony_ci * void my_drain_stream_func(pa_threaded_mainloop *m, pa_stream *s) {
18353a5a1b3Sopenharmony_ci *     pa_operation *o;
18453a5a1b3Sopenharmony_ci *
18553a5a1b3Sopenharmony_ci *     pa_threaded_mainloop_lock(m);
18653a5a1b3Sopenharmony_ci *
18753a5a1b3Sopenharmony_ci *     o = pa_stream_drain(s, my_drain_callback, m);
18853a5a1b3Sopenharmony_ci *     assert(o);
18953a5a1b3Sopenharmony_ci *
19053a5a1b3Sopenharmony_ci *     while (drain_result == NULL)
19153a5a1b3Sopenharmony_ci *         pa_threaded_mainloop_wait(m);
19253a5a1b3Sopenharmony_ci *
19353a5a1b3Sopenharmony_ci *     pa_operation_unref(o);
19453a5a1b3Sopenharmony_ci *
19553a5a1b3Sopenharmony_ci *     if (*drain_result)
19653a5a1b3Sopenharmony_ci *         printf("Success!");
19753a5a1b3Sopenharmony_ci *     else
19853a5a1b3Sopenharmony_ci *         printf("Bitter defeat...");
19953a5a1b3Sopenharmony_ci *
20053a5a1b3Sopenharmony_ci *     pa_threaded_mainloop_accept(m);
20153a5a1b3Sopenharmony_ci *
20253a5a1b3Sopenharmony_ci *     pa_threaded_mainloop_unlock(m);
20353a5a1b3Sopenharmony_ci * }
20453a5a1b3Sopenharmony_ci * \endcode
20553a5a1b3Sopenharmony_ci *
20653a5a1b3Sopenharmony_ci * The example is a bit silly as it would probably have been easier to just
20753a5a1b3Sopenharmony_ci * copy the contents of success, but for larger data structures this can be
20853a5a1b3Sopenharmony_ci * wasteful.
20953a5a1b3Sopenharmony_ci *
21053a5a1b3Sopenharmony_ci * The difference here compared to the basic callback is the value 1 passed
21153a5a1b3Sopenharmony_ci * to pa_threaded_mainloop_signal() and the call to
21253a5a1b3Sopenharmony_ci * pa_threaded_mainloop_accept(). What will happen is that
21353a5a1b3Sopenharmony_ci * pa_threaded_mainloop_signal() will signal the main function and then wait.
21453a5a1b3Sopenharmony_ci * The main function is then free to use the data in the callback until
21553a5a1b3Sopenharmony_ci * pa_threaded_mainloop_accept() is called, which will allow the callback
21653a5a1b3Sopenharmony_ci * to continue.
21753a5a1b3Sopenharmony_ci *
21853a5a1b3Sopenharmony_ci * Note that pa_threaded_mainloop_accept() must be called some time between
21953a5a1b3Sopenharmony_ci * exiting the while loop and unlocking the main loop! Failure to do so will
22053a5a1b3Sopenharmony_ci * result in a race condition. I.e. it is not ok to release the lock and
22153a5a1b3Sopenharmony_ci * regrab it before calling pa_threaded_mainloop_accept().
22253a5a1b3Sopenharmony_ci *
22353a5a1b3Sopenharmony_ci * \subsection async_subsec Asynchronous callbacks
22453a5a1b3Sopenharmony_ci *
22553a5a1b3Sopenharmony_ci * PulseAudio also has callbacks that are completely asynchronous, meaning
22653a5a1b3Sopenharmony_ci * that they can be called at any time. The threaded main loop API provides
22753a5a1b3Sopenharmony_ci * the locking mechanism to handle concurrent accesses, but nothing else.
22853a5a1b3Sopenharmony_ci * Applications will have to handle communication from the callback to the
22953a5a1b3Sopenharmony_ci * main program through their own mechanisms.
23053a5a1b3Sopenharmony_ci *
23153a5a1b3Sopenharmony_ci * The callbacks that are completely asynchronous are:
23253a5a1b3Sopenharmony_ci *
23353a5a1b3Sopenharmony_ci * \li State callbacks for contexts, streams, etc.
23453a5a1b3Sopenharmony_ci * \li Subscription notifications
23553a5a1b3Sopenharmony_ci */
23653a5a1b3Sopenharmony_ci
23753a5a1b3Sopenharmony_ci/** \file
23853a5a1b3Sopenharmony_ci *
23953a5a1b3Sopenharmony_ci * A thread based event loop implementation based on pa_mainloop. The
24053a5a1b3Sopenharmony_ci * event loop is run in a helper thread in the background. A few
24153a5a1b3Sopenharmony_ci * synchronization primitives are available to access the objects
24253a5a1b3Sopenharmony_ci * attached to the event loop safely.
24353a5a1b3Sopenharmony_ci *
24453a5a1b3Sopenharmony_ci * See also \subpage threaded_mainloop
24553a5a1b3Sopenharmony_ci */
24653a5a1b3Sopenharmony_ci
24753a5a1b3Sopenharmony_ci/** An opaque threaded main loop object */
24853a5a1b3Sopenharmony_citypedef struct pa_threaded_mainloop pa_threaded_mainloop;
24953a5a1b3Sopenharmony_ci
25053a5a1b3Sopenharmony_ci/** Allocate a new threaded main loop object. You have to call
25153a5a1b3Sopenharmony_ci * pa_threaded_mainloop_start() before the event loop thread starts
25253a5a1b3Sopenharmony_ci * running. Free with pa_threaded_mainloop_free. */
25353a5a1b3Sopenharmony_cipa_threaded_mainloop *pa_threaded_mainloop_new(void);
25453a5a1b3Sopenharmony_ci
25553a5a1b3Sopenharmony_ci/** Free a threaded main loop object. If the event loop thread is
25653a5a1b3Sopenharmony_ci * still running, terminate it with pa_threaded_mainloop_stop()
25753a5a1b3Sopenharmony_ci * first. */
25853a5a1b3Sopenharmony_civoid pa_threaded_mainloop_free(pa_threaded_mainloop* m);
25953a5a1b3Sopenharmony_ci
26053a5a1b3Sopenharmony_ci/** Start the event loop thread. Returns zero on success, negative on error. */
26153a5a1b3Sopenharmony_ciint pa_threaded_mainloop_start(pa_threaded_mainloop *m);
26253a5a1b3Sopenharmony_ci
26353a5a1b3Sopenharmony_ci/** Terminate the event loop thread cleanly. Make sure to unlock the
26453a5a1b3Sopenharmony_ci * mainloop object before calling this function. */
26553a5a1b3Sopenharmony_civoid pa_threaded_mainloop_stop(pa_threaded_mainloop *m);
26653a5a1b3Sopenharmony_ci
26753a5a1b3Sopenharmony_ci/** Lock the event loop object, effectively blocking the event loop
26853a5a1b3Sopenharmony_ci * thread from processing events. You can use this to enforce
26953a5a1b3Sopenharmony_ci * exclusive access to all objects attached to the event loop. This
27053a5a1b3Sopenharmony_ci * lock is recursive. This function may not be called inside the event
27153a5a1b3Sopenharmony_ci * loop thread. Events that are dispatched from the event loop thread
27253a5a1b3Sopenharmony_ci * are executed with this lock held. */
27353a5a1b3Sopenharmony_civoid pa_threaded_mainloop_lock(pa_threaded_mainloop *m);
27453a5a1b3Sopenharmony_ci
27553a5a1b3Sopenharmony_ci/** Unlock the event loop object, inverse of pa_threaded_mainloop_lock(). */
27653a5a1b3Sopenharmony_civoid pa_threaded_mainloop_unlock(pa_threaded_mainloop *m);
27753a5a1b3Sopenharmony_ci
27853a5a1b3Sopenharmony_ci/** Wait for an event to be signalled by the event loop thread. You
27953a5a1b3Sopenharmony_ci * can use this to pass data from the event loop thread to the main
28053a5a1b3Sopenharmony_ci * thread in a synchronized fashion. This function may not be called
28153a5a1b3Sopenharmony_ci * inside the event loop thread. Prior to this call the event loop
28253a5a1b3Sopenharmony_ci * object needs to be locked using pa_threaded_mainloop_lock(). While
28353a5a1b3Sopenharmony_ci * waiting the lock will be released. Immediately before returning it
28453a5a1b3Sopenharmony_ci * will be acquired again. This function may spuriously wake up even
28553a5a1b3Sopenharmony_ci * without pa_threaded_mainloop_signal() being called. You need to
28653a5a1b3Sopenharmony_ci * make sure to handle that! */
28753a5a1b3Sopenharmony_civoid pa_threaded_mainloop_wait(pa_threaded_mainloop *m);
28853a5a1b3Sopenharmony_ci
28953a5a1b3Sopenharmony_ci/** Signal all threads waiting for a signalling event in
29053a5a1b3Sopenharmony_ci * pa_threaded_mainloop_wait(). If wait_for_accept is non-zero, do
29153a5a1b3Sopenharmony_ci * not return before the signal was accepted by a
29253a5a1b3Sopenharmony_ci * pa_threaded_mainloop_accept() call. While waiting for that condition
29353a5a1b3Sopenharmony_ci * the event loop object is unlocked. */
29453a5a1b3Sopenharmony_civoid pa_threaded_mainloop_signal(pa_threaded_mainloop *m, int wait_for_accept);
29553a5a1b3Sopenharmony_ci
29653a5a1b3Sopenharmony_ci/** Accept a signal from the event thread issued with
29753a5a1b3Sopenharmony_ci * pa_threaded_mainloop_signal(). This call should only be used in
29853a5a1b3Sopenharmony_ci * conjunction with pa_threaded_mainloop_signal() with a non-zero
29953a5a1b3Sopenharmony_ci * wait_for_accept value.  */
30053a5a1b3Sopenharmony_civoid pa_threaded_mainloop_accept(pa_threaded_mainloop *m);
30153a5a1b3Sopenharmony_ci
30253a5a1b3Sopenharmony_ci/** Return the return value as specified with the main loop's
30353a5a1b3Sopenharmony_ci * pa_mainloop_quit() routine. */
30453a5a1b3Sopenharmony_ciint pa_threaded_mainloop_get_retval(const pa_threaded_mainloop *m);
30553a5a1b3Sopenharmony_ci
30653a5a1b3Sopenharmony_ci/** Return the main loop abstraction layer vtable for this main loop.
30753a5a1b3Sopenharmony_ci * There is no need to free this object as it is owned by the loop
30853a5a1b3Sopenharmony_ci * and is destroyed when the loop is freed. */
30953a5a1b3Sopenharmony_cipa_mainloop_api* pa_threaded_mainloop_get_api(pa_threaded_mainloop*m);
31053a5a1b3Sopenharmony_ci
31153a5a1b3Sopenharmony_ci/** Returns non-zero when called from within the event loop thread. \since 0.9.7 */
31253a5a1b3Sopenharmony_ciint pa_threaded_mainloop_in_thread(pa_threaded_mainloop *m);
31353a5a1b3Sopenharmony_ci
31453a5a1b3Sopenharmony_ci/** Sets the name of the thread. \since 5.0 */
31553a5a1b3Sopenharmony_civoid pa_threaded_mainloop_set_name(pa_threaded_mainloop *m, const char *name);
31653a5a1b3Sopenharmony_ci
31753a5a1b3Sopenharmony_ci/** Runs the given callback in the mainloop thread without the lock held. The
31853a5a1b3Sopenharmony_ci * caller is responsible for ensuring that PulseAudio data structures are only
31953a5a1b3Sopenharmony_ci * accessed in a thread-safe way (that is, APIs that take pa_context and
32053a5a1b3Sopenharmony_ci * pa_stream are not thread-safe, and should not accessed without some
32153a5a1b3Sopenharmony_ci * synchronisation). This is the only situation in which
32253a5a1b3Sopenharmony_ci * pa_threaded_mainloop_lock() and pa_threaded_mainloop_unlock() may be used
32353a5a1b3Sopenharmony_ci * in the mainloop thread context. \since 13.0 */
32453a5a1b3Sopenharmony_civoid pa_threaded_mainloop_once_unlocked(pa_threaded_mainloop *m, void (*callback)(pa_threaded_mainloop *m, void *userdata),
32553a5a1b3Sopenharmony_ci        void *userdata);
32653a5a1b3Sopenharmony_ci
32753a5a1b3Sopenharmony_ciPA_C_DECL_END
32853a5a1b3Sopenharmony_ci
32953a5a1b3Sopenharmony_ci#endif
330