Commit graph

327 commits

Author SHA1 Message Date
Pauli Virtanen
1ec814977c logger: support logging local timestamps and other timestamp logs
In timestamps, support different clocks and local time as formats.

Local real time timestamps are useful when trying to correlate logs from
different sources.
2025-01-13 13:48:22 +00:00
Wim Taymans
a4b553f3d4 spa: serialize in_thread flushes with a mutex
When we have no thread running the loop, we need to flush the queues
from the invoking thread. Make sure that when multiple threads attempt
this that we serialize the flushing because the flushing code is not
thread safe.
2024-12-03 16:38:28 +01:00
Wim Taymans
8c59fae42d loop: add overflow queues again
Add the overflow queues again. We can easily iterate atomically over the
overflow queues and flush them.

Overflowing a queue is quite common when heavy swapping is done and
should never cause a lockup, so allocate new queues as we need them. We
can share the eventfd with the main queue to avoid wastings fds.

The limit on the number of queues is then only for when concurrent
threads want to invoke things, so 128 is plenty enough.
2024-11-14 17:38:43 +01:00
Wim Taymans
6cf320e387 loop: handle queue overflow better
When a queue overflows we place the queue back in the stack and try
again. Because it's at the top of the stack we take exactly the same
queue and keep on looping forever if the other thread is blocked for
some reason.

Instead, mark the queue as overflowed and only place it back in the
stack when we have flushed it.

This avoids a deadlock when the main-thread invokes on the data loop
and blocks and when the data loop invokes on the main-thread and
overflows the queue.
2024-11-14 15:58:09 +01:00
Wim Taymans
9c19284f7f support: make the loop queue handling lockfree
Don't use TSS to store per-thread queues but keep a lockfree stack of
queues. We can then pick off a queue and write to that one and place it
back after use.

We need to keep the queues indexed by id in the stack because otherwise
we would need to compare-and-swap 128 bits (pointer + tag), which is
more problematic.

Because we keep the queues in an array and no queue is ever removed and
the array can only grow, we can quite easily just iterate the array
without a lock. Without the lock we also fix one of the potential
problems with ardour where the queue_flush thread is canceled while
flushing and the queue_mutex remains locked.

Because we end up with all queues in the array now, we can overflow the
fixed max amount of queues we can manage. When that happens, sleep for a
while and try again. This is a case where more than QUEUES_MAX (128) threads
are invoking at the same time and is rather unlikely.

There is also the queue overflow case which we now also must handle with
a retry. This potentially uses more eventfds but again this should be
unlikely and cause no further problems.

See #4356
2024-11-04 17:41:14 +01:00
Wim Taymans
22c45af7e0 loop: refcount the queues
The loop in the TSS gets an extra refcount and is unreffed when the TSS
destroy is called.

We can then also ref the queue during the function callback. When the
queue (thread) was destroyed during the callback, ignore the result and
continue with the next queues.

See #4356
2024-10-21 17:47:31 +02:00
Wim Taymans
bb53aa08ad loop: warn when some queues are still in TSS
When we clear we need to have all our queues removed from the TSS when
we delete the tss key or else they are leaked, check an warn about this
using a refcount of queued in the TSS.

See #4356
2024-10-21 17:08:10 +02:00
Wim Taymans
c4fece74a5 loop: fix race in shutdown
Make it possible to call loop_queue_destroy() from both the TSS destroy
and impl_clear() without races. We make sure that only one can remove
the queue from the queue list and cleanup. We also store the IN_TSS flag
in the flags so that we can see them before the queue is added to the
queue list. Only free the IN_TSS queue when the TSS destroy is called.

See #4356
2024-10-21 16:45:17 +02:00
Wim Taymans
dca11e6c41 loop: remove extra allocation
We don't actually need the extra allocation for the tss. We can just
mark the queue as being in the tss. When a queue is destroyed, mark it
as destroyed but when it is still in the tss, don't free the structure
yet. We free the structure when we destroy the tss.

We can also free the overflow queues of a queue when it is destroyed
immediately.
2024-10-02 09:40:54 +02:00
Wim Taymans
5d3aac313d loop: free tss from the thread calling impl::clear
The thread that calls the impl_clear method might be the main thread and
is certainly not going to call the invoke function anymore so free the
tss if there is any.

Fixes a leak in the unit test.
2024-10-02 09:21:00 +02:00
Wim Taymans
82585b7475 loop: improve tss cleanup
Store a pointer to a pointer to a queue in the tss and point to it from
the queue.

When we destroy the queue when we _clear the support, we can clear the
pointer in the tss as well. This way, when the thread is later
destroyed, it will see the NULL pointer and not try to free the queue
again.
2024-10-01 13:25:15 +02:00
Gleb Popov
50dab6dda6 meson: Search for and link to stdthreads 2024-09-23 08:09:45 +00:00
Gleb Popov
67ddfc3053 Use the 'thrd_success' constant when checking for tss_create result 2024-09-23 08:09:45 +00:00
Barnabás Pőcze
86004ba3f1 spa: support: use feature macro from config.h
Fixes 8166b9c580 ("spa/support: implement RISCV V CPU detection")
2024-09-18 22:29:11 +02:00
sunyuechi
8166b9c580 spa/support: implement RISCV V CPU detection 2024-09-18 10:40:48 +00:00
Wim Taymans
e2991f6398 json: add helper function to parse channel positions
Use the helper instead of duplicating the same code.

Also add some helpers to parse a json array of uint32_t

Move some functions to convert between type name and id.
2024-09-18 09:54:34 +02:00
Wim Taymans
cd81b5f39a spa: add spa_json_begin_array/object and relaxed versions
Add spa_json_begin_array/object to replace
spa_json_init+spa_json_begin_array/object

This function is better because it does not waste a useless spa_json
structure as an iterator. The relaxed versions also error out when the
container is mismatched because parsing a mismatched container is not
going to give any results anyway.
2024-09-16 09:50:33 +02:00
Wim Taymans
fff52bb7a2 Revert "spa: support: loop: do not call control hooks on blocking invoke"
This reverts commit 9ae89b4247.

All invokes should be paired with a lock/unlock if the loop requires
this. For internal calls of invoke, this will also be true because all
pipewire functions should be called with the lock.

Fixes #4215
2024-08-21 14:48:54 +02:00
Wim Taymans
8c1a69f1b5 loop: don't usleep when queue is full
When the queue is full, before this patch we used to go into usleep in
the hope that the other thread will run and empty the queue and that we
can retry after the usleep.

This however does not always work because the other thread might be waiting
for the thread that does the invoke call and we lock forever.

Therefore we should always try to make progress in some way. Instead of
waiting, allocate an (or use the previously allocated) overflow queue and
write to that one. We can chain multiple overflow queues together as many
as we need (but we might want to bound that as well).

The loop.retry-timeout property is now deprecated.

See #4114
2024-08-06 12:05:11 +02:00
Barnabás Pőcze
9ae89b4247 spa: support: loop: do not call control hooks on blocking invoke
The control hooks of a loop are called before the loop starts polling
and after it has finished polling. Currently, this is used to implement
the locking in pw_thread_loop. This is used to guarantee that the thread
loop's lock is taken while the thread loop is dispatching, and that
the lock can be taken while the loop is polling, when it is running
no user-space code.

However, calling the thread control hooks of thread A when doing an
blocking invoke from thread B serves little purpose, and in fact
can cause issues: for example, issuing a blocking invoke on a
pw_thread_loop does not work unless the lock thereof is taken.

This behaviour, of calling the control hooks from other threads,
is also not documented, and goes contrary to what is currently
stated in the loop.h header file:

  /** Executed right before waiting for events. It is typically used to
   * release locks. */
  ...
  /** Executed right after waiting for events. It is typically used to
   * reacquire locks. */

At the moment the implementation allows any thread to queue invoke
items on any other thread without restrictions; calling the control
hooks only places extra restrictions on the usability of this mechanism
(in case of pw_thread_loop, having to take the loop's lock).
So do not call the control hooks when doing a blocking invoke.
2024-08-05 18:14:39 +00:00
Wim Taymans
494600d46a loop: release queue lock before calling invoke function
We don't actually need to hold the lock while calling the invoke
function, we only need the lock to protect the list of queues.
2024-07-30 12:04:42 +02:00
Wim Taymans
2a8a08f303 loop: signal when queue is full
When our queue is full, signal the wakeup event to make sure the thread
will wake up and try to clear the queue before we go to sleep.
2024-07-20 14:05:09 +02:00
Wim Taymans
d4515378e7 node-driver: 5 seconds of freewheel timeout is enough
We retry to run the graph every 5 seconds in case it didn't complete. A
10 seconds timeout feels quite long.
2024-07-12 12:25:18 +02:00
Wim Taymans
42096de3cc node: add a clock XRUN_RECOVER flag
Make a new flag that is set when the process function is called because
of a recover from a graph xrun.

Use this flag in the freewheel driver to detect a recover and to avoid
scheduling a new timeout. We should schedule a new timeout only when the
process function was called after completion.

This fixes export in ardour some more when the initial driver timeout
didn't complete (when, for example, some nodes were still starting up).
2024-07-12 12:21:59 +02:00
David Coles
9ae9009edf Define setlinebuf for MSVC
According to `setbuf(3)`, `setlinebuf` is exactly equivalent to
`setvbuf(stream, NULL, _IOLBF, 0)`.
2024-07-01 15:28:58 +00:00
David Coles
2770e96e08 loop: fix update_timer handling of solo repeat argument
I believe the intent here is that if a `interval` is provided
but `value` is unset, then `value` should default to `period`
so the timer first fires after one `interval`.

Since `interval` is always a relative duration, `value` should
be interpreted as a relative duration, not an absolute one.
2024-06-30 18:37:49 +00:00
Wim Taymans
1ae4374ccf Fix compilation with -Werror=float-conversion
Better make the conversions explicit so that we don't get any surprises.

Fixes #4065
2024-06-18 12:17:56 +02:00
Wim Taymans
8b23a8a89e loop: flush items in the order they were added
Add a count to each invoke item that is updated with an increasing
loop atomic counter. Flush items from the queues based on their count
so that items are flushed in the order they were added even if they
were added to different queues.
2024-05-08 12:21:54 +02:00
Wim Taymans
8ff40e6252 loop: improve in_thread handling of invoke queue
Because we now have a dedicated queue per thread, we can simply add our
invoke item to the queue and then flush all the queues when we are
running in the thread of the loop.

This simplifies some things and removes potential out-of-order messages
that got queued while flushing.
2024-04-29 15:56:00 +02:00
Wim Taymans
de0db48f17 loop: create a per-thread queue
Keep a thread local queue. This makes it possible for multiple threads
to write to the ringbuffer.

There is a lock to protect the list of queues. It can only be contended
when new queues are created in the threads but this can be done at
thread startup.

Fixes #3983
2024-04-29 15:17:45 +02:00
Wim Taymans
c76424da36 loop: move invoke queue to separate object
Make an internal queue object that implements the invoke queue.

Because we can not do invokes concurrently from different threads, this
is required to make per-thread invoke queues later.
2024-04-29 12:10:48 +02:00
Pauli Virtanen
ac35ecf329 journal: prepend code location to messages at debug log levels
Debug and trace log messages are often written based on the stderr
logging, where code location is always visible.

journalctl does not show the code location without extra tricks,
which makes user-submitted debug logs from journal more cryptic.

Make journal log more similar to stderr logs by prepending the code
location and log level in the log message when the log topic
level is >= DEBUG.
2024-04-28 16:02:28 +03:00
Barnabás Pőcze
6a26e6dd3f treewide: fix some format string issues
Use the proper specifier, and cast to a known type where the type
is not guaranteed by any standard.

See #3975
2024-04-25 07:24:10 +00:00
Wim Taymans
af310523db spa: improve null-audio-sink channels
We can just update the channels in the props, we don't need an extra
property that can go out of sync with the channels.

See #3931
2024-03-28 17:11:16 +01:00
Samuel Thibault
7ee8192ce9 spa plugins: Include Linux headers on Linux only 2024-03-25 14:53:14 +00:00
Pauli Virtanen
e784de3933 spa: use log topics everywhere
Use log topics properly everywhere, convert from "#define NAME".
2024-03-11 18:45:21 +02:00
Pauli Virtanen
7d0ca2d103 spa: node-driver: always put CLOCK_MONOTONIC values to clock->nsec
When timer is not using monotonic clock, apply clock offset to translate
the time values to the monotonic clock when putting them to spa_io_clock
nsec fields.

Get appropriate clock offset by smoothed filtering.  The parameters here
keep the offset jitter < 10ns or so.

As monotonic/boottime/realtime all contain adjtime(), there generally is
no drift in the offset here, so just averaging should be fine.

Also fix using wrong timer clock when freewheeling.
2024-03-07 20:04:54 +02:00
Jonas Holmberg
e78e97cb99 pipewire-alsa: Propagate errors from eventfd().
Propagate the error if spa_system_eventfd_create() fails. Also copy
errno before calling spa_log_debug() in spa_system_eventfd_create() to
make sure it is not overwritten.
2024-02-19 14:16:26 +00:00
Ruben Gonzalez
15bdab89c3 logger: minor performance improvement to avoid syscall done by isatty 2024-02-17 11:42:12 +00:00
Wim Taymans
532bc878f4 spa: use errno values in warnings
Propagate the errno values from syscalls and use them in the warning
messages to give info about what is going on.
2024-02-12 10:01:22 +01:00
Dmitry Sharshakov
bb2f793598 node-driver: suggest user to check clock device permissions 2024-02-12 08:14:10 +00:00
Wim Taymans
eb33145691 loop: fix clang compilation 2024-02-05 23:16:36 +01:00
Barnabás Pőcze
a834da988c spa: support: add missing static 2024-02-05 20:01:21 +01:00
Wim Taymans
e7e6742200 loop: sleep and retry when the invoke queue is full
When the invoke ringbuffer is full, sleep a little and try again.
Add an option to set the retty timeout, setting this to 0 restores
the old behaviour of returning -EPIPE.

Most callers don't check the return values and might assume the invoke
call is queued or executed, which could cause crashes or leaks.

When the queue overruns, it's better to log a warning and hope that the
problem is resolved soon. We might abort or return the error to the
caller later if we want to break the retry loop.

See !1887
2024-02-05 19:44:02 +01:00
Arun Raghavan
3958bed5c3 node-driver: Log when we resync 2024-01-29 12:08:15 -05:00
Dmitry Sharshakov
ca25066874 node-driver: allow fractional resync-ms 2024-01-24 20:52:08 +03:00
Wim Taymans
e7888d4ccc support: add resync.ms option to node.driver
Move some of the tracking code for the DLL to where it is used.

Add resync.ms (default 10) option at which we give up rate adjusting
and instead do a hard resync. This results in a jump in the position
of the graph clock.
2024-01-24 17:53:15 +01:00
Wim Taymans
15908328d1 support: fix freewheel timeout in node-driver
When freewheeling we will immediately schedule a new graph cycle when we
get a process call because the graph completed.

When the process call is not done, because of some xrun or
because some node was removed that causes the graph to fail completion,
The next cycle will happen after a timeout.

This timeout was calculated as the ideal wakeup time (after a quantum of
time) and would accumulate for each timeout. The result is that the
timeout ended up far in the future and would stall the freewheel driver
for a long time.

Fix this by always setting the next timeout to wakeup time + freewheel.timeout
seconds. Also add a config property for the timeout (10 seconds, like
jack2 by default).
2024-01-10 11:59:10 +01:00
Wim Taymans
e088dd2d2f journal: copy log level to chained logger
Make sure the log level on the chained logger is the same as ours.

Makes PIPEWIRE_DEBUG=3 make run print debug again.

This used to work because the log level was parsed and set before the
loggers were created and chained, and so they all got the same level.

Now that the level can be changed with metadata at runtime, we can't
really update all past loggers so let the journal logger copy the
level itself.
2024-01-04 13:57:26 +01:00
Pauli Virtanen
53ba3d0e4c spa: support: remove log pattern support
The log patterns are now handled by plugin host.
2024-01-04 10:02:55 +00:00