Coverage Report

Created: 2025-06-12 07:21

/src/mpv/misc/rendezvous.c
Line
Count
Source (jump to first uncovered line)
1
2
#include "rendezvous.h"
3
4
#include "osdep/threads.h"
5
6
static mp_static_mutex lock = MP_STATIC_MUTEX_INITIALIZER;
7
static mp_cond wakeup = MP_STATIC_COND_INITIALIZER;
8
9
static struct waiter *waiters;
10
11
struct waiter {
12
    void *tag;
13
    struct waiter *next;
14
    intptr_t *value;
15
};
16
17
/* A barrier for 2 threads, which can exchange a value when they meet.
18
 * The first thread to call this function will block. As soon as two threads
19
 * are calling this function with the same tag value, they will unblock, and
20
 * on each thread the call returns the value parameter of the _other_ thread.
21
 *
22
 * tag is an arbitrary value, but it must be an unique pointer. If there are
23
 * more than 2 threads using the same tag, things won't work. Typically, it
24
 * will have to point to a memory allocation or to the stack, while pointing
25
 * it to static data is always a bug.
26
 *
27
 * This shouldn't be used for performance critical code (uses a linked list
28
 * of _all_ waiters in the process, and temporarily wakes up _all_ waiters on
29
 * each second call).
30
 *
31
 * This is inspired by: https://man.cat-v.org/plan_9/2/rendezvous */
32
intptr_t mp_rendezvous(void *tag, intptr_t value)
33
130k
{
34
130k
    struct waiter wait = { .tag = tag, .value = &value };
35
130k
    mp_mutex_lock(&lock);
36
130k
    struct waiter **prev = &waiters;
37
130k
    while (*prev) {
38
65.3k
        if ((*prev)->tag == tag) {
39
65.3k
            intptr_t tmp = *(*prev)->value;
40
65.3k
            *(*prev)->value = value;
41
65.3k
            value = tmp;
42
65.3k
            (*prev)->value = NULL; // signals completion
43
65.3k
            *prev = (*prev)->next; // unlink
44
65.3k
            mp_cond_broadcast(&wakeup);
45
65.3k
            goto done;
46
65.3k
        }
47
0
        prev = &(*prev)->next;
48
0
    }
49
65.3k
    *prev = &wait;
50
130k
    while (wait.value)
51
65.3k
        mp_cond_wait(&wakeup, &lock);
52
130k
done:
53
130k
    mp_mutex_unlock(&lock);
54
130k
    return value;
55
65.3k
}