153a5a1b3Sopenharmony_ci/***
253a5a1b3Sopenharmony_ci  This file is part of PulseAudio.
353a5a1b3Sopenharmony_ci
453a5a1b3Sopenharmony_ci  Copyright 2008 Lennart Poettering
553a5a1b3Sopenharmony_ci
653a5a1b3Sopenharmony_ci  PulseAudio is free software; you can redistribute it and/or modify
753a5a1b3Sopenharmony_ci  it under the terms of the GNU Lesser General Public License as published
853a5a1b3Sopenharmony_ci  by the Free Software Foundation; either version 2.1 of the License,
953a5a1b3Sopenharmony_ci  or (at your option) any later version.
1053a5a1b3Sopenharmony_ci
1153a5a1b3Sopenharmony_ci  PulseAudio is distributed in the hope that it will be useful, but
1253a5a1b3Sopenharmony_ci  WITHOUT ANY WARRANTY; without even the implied warranty of
1353a5a1b3Sopenharmony_ci  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1453a5a1b3Sopenharmony_ci  General Public License for more details.
1553a5a1b3Sopenharmony_ci
1653a5a1b3Sopenharmony_ci  You should have received a copy of the GNU Lesser General Public License
1753a5a1b3Sopenharmony_ci  along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
1853a5a1b3Sopenharmony_ci***/
1953a5a1b3Sopenharmony_ci
2053a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H
2153a5a1b3Sopenharmony_ci#include <config.h>
2253a5a1b3Sopenharmony_ci#endif
2353a5a1b3Sopenharmony_ci
2453a5a1b3Sopenharmony_ci#include <errno.h>
2553a5a1b3Sopenharmony_ci#include <string.h>
2653a5a1b3Sopenharmony_ci#include <signal.h>
2753a5a1b3Sopenharmony_ci
2853a5a1b3Sopenharmony_ci#ifdef HAVE_PTHREAD
2953a5a1b3Sopenharmony_ci#include <pthread.h>
3053a5a1b3Sopenharmony_ci#endif
3153a5a1b3Sopenharmony_ci
3253a5a1b3Sopenharmony_ci#include <pulse/gccmacro.h>
3353a5a1b3Sopenharmony_ci#include <pulse/xmalloc.h>
3453a5a1b3Sopenharmony_ci
3553a5a1b3Sopenharmony_ci#include <pulsecore/i18n.h>
3653a5a1b3Sopenharmony_ci#include <pulsecore/poll.h>
3753a5a1b3Sopenharmony_ci#include <pulsecore/mutex.h>
3853a5a1b3Sopenharmony_ci#include <pulsecore/thread.h>
3953a5a1b3Sopenharmony_ci#include <pulsecore/core-util.h>
4053a5a1b3Sopenharmony_ci
4153a5a1b3Sopenharmony_ci#include "lock-autospawn.h"
4253a5a1b3Sopenharmony_ci
4353a5a1b3Sopenharmony_ci/* So, why do we have this complex code here with threads and pipes
4453a5a1b3Sopenharmony_ci * and stuff? For two reasons: POSIX file locks are per-process, not
4553a5a1b3Sopenharmony_ci * per-file descriptor. That means that two contexts within the same
4653a5a1b3Sopenharmony_ci * process that try to create the autospawn lock might end up assuming
4753a5a1b3Sopenharmony_ci * they both managed to lock the file. And then, POSIX locking
4853a5a1b3Sopenharmony_ci * operations are synchronous. If two contexts run from the same event
4953a5a1b3Sopenharmony_ci * loop it must be made sure that they do not block each other, but
5053a5a1b3Sopenharmony_ci * that the locking operation can happen asynchronously. */
5153a5a1b3Sopenharmony_ci
5253a5a1b3Sopenharmony_ci#define AUTOSPAWN_LOCK "autospawn.lock"
5353a5a1b3Sopenharmony_ci
5453a5a1b3Sopenharmony_cistatic pa_mutex *mutex;
5553a5a1b3Sopenharmony_ci
5653a5a1b3Sopenharmony_cistatic unsigned n_ref = 0;
5753a5a1b3Sopenharmony_cistatic int lock_fd = -1;
5853a5a1b3Sopenharmony_cistatic pa_mutex *lock_fd_mutex = NULL;
5953a5a1b3Sopenharmony_cistatic pa_thread *thread = NULL;
6053a5a1b3Sopenharmony_cistatic int pipe_fd[2] = { -1, -1 };
6153a5a1b3Sopenharmony_ci
6253a5a1b3Sopenharmony_cistatic enum {
6353a5a1b3Sopenharmony_ci    STATE_IDLE,
6453a5a1b3Sopenharmony_ci    STATE_OWNING,
6553a5a1b3Sopenharmony_ci    STATE_TAKEN,
6653a5a1b3Sopenharmony_ci    STATE_FAILED
6753a5a1b3Sopenharmony_ci} state = STATE_IDLE;
6853a5a1b3Sopenharmony_ci
6953a5a1b3Sopenharmony_cistatic void destroy_mutex(void) PA_GCC_DESTRUCTOR;
7053a5a1b3Sopenharmony_ci
7153a5a1b3Sopenharmony_cistatic int ref(void) {
7253a5a1b3Sopenharmony_ci
7353a5a1b3Sopenharmony_ci    if (n_ref > 0) {
7453a5a1b3Sopenharmony_ci
7553a5a1b3Sopenharmony_ci        pa_assert(pipe_fd[0] >= 0);
7653a5a1b3Sopenharmony_ci        pa_assert(pipe_fd[1] >= 0);
7753a5a1b3Sopenharmony_ci        pa_assert(lock_fd_mutex);
7853a5a1b3Sopenharmony_ci
7953a5a1b3Sopenharmony_ci        n_ref++;
8053a5a1b3Sopenharmony_ci
8153a5a1b3Sopenharmony_ci        return 0;
8253a5a1b3Sopenharmony_ci    }
8353a5a1b3Sopenharmony_ci
8453a5a1b3Sopenharmony_ci    pa_assert(!lock_fd_mutex);
8553a5a1b3Sopenharmony_ci    pa_assert(state == STATE_IDLE);
8653a5a1b3Sopenharmony_ci    pa_assert(lock_fd < 0);
8753a5a1b3Sopenharmony_ci    pa_assert(!thread);
8853a5a1b3Sopenharmony_ci    pa_assert(pipe_fd[0] < 0);
8953a5a1b3Sopenharmony_ci    pa_assert(pipe_fd[1] < 0);
9053a5a1b3Sopenharmony_ci
9153a5a1b3Sopenharmony_ci    if (pa_pipe_cloexec(pipe_fd) < 0)
9253a5a1b3Sopenharmony_ci        return -1;
9353a5a1b3Sopenharmony_ci
9453a5a1b3Sopenharmony_ci    pa_make_fd_nonblock(pipe_fd[1]);
9553a5a1b3Sopenharmony_ci    pa_make_fd_nonblock(pipe_fd[0]);
9653a5a1b3Sopenharmony_ci
9753a5a1b3Sopenharmony_ci    lock_fd_mutex = pa_mutex_new(false, false);
9853a5a1b3Sopenharmony_ci
9953a5a1b3Sopenharmony_ci    n_ref = 1;
10053a5a1b3Sopenharmony_ci    return 0;
10153a5a1b3Sopenharmony_ci}
10253a5a1b3Sopenharmony_ci
10353a5a1b3Sopenharmony_cistatic void unref(bool after_fork) {
10453a5a1b3Sopenharmony_ci
10553a5a1b3Sopenharmony_ci    pa_assert(n_ref > 0);
10653a5a1b3Sopenharmony_ci    pa_assert(pipe_fd[0] >= 0);
10753a5a1b3Sopenharmony_ci    pa_assert(pipe_fd[1] >= 0);
10853a5a1b3Sopenharmony_ci    pa_assert(lock_fd_mutex);
10953a5a1b3Sopenharmony_ci
11053a5a1b3Sopenharmony_ci    n_ref--;
11153a5a1b3Sopenharmony_ci
11253a5a1b3Sopenharmony_ci    if (n_ref > 0)
11353a5a1b3Sopenharmony_ci        return;
11453a5a1b3Sopenharmony_ci
11553a5a1b3Sopenharmony_ci    /* Join threads only in the process the new thread was created in
11653a5a1b3Sopenharmony_ci     * to avoid undefined behaviour.
11753a5a1b3Sopenharmony_ci     * POSIX.1-2008 XSH 2.9.2 Thread IDs: "applications should only assume
11853a5a1b3Sopenharmony_ci     * that thread IDs are usable and unique within a single process." */
11953a5a1b3Sopenharmony_ci    if (thread) {
12053a5a1b3Sopenharmony_ci        if (after_fork)
12153a5a1b3Sopenharmony_ci            pa_thread_free_nojoin(thread);
12253a5a1b3Sopenharmony_ci	else
12353a5a1b3Sopenharmony_ci            pa_thread_free(thread);
12453a5a1b3Sopenharmony_ci        thread = NULL;
12553a5a1b3Sopenharmony_ci    }
12653a5a1b3Sopenharmony_ci
12753a5a1b3Sopenharmony_ci    pa_mutex_lock(lock_fd_mutex);
12853a5a1b3Sopenharmony_ci
12953a5a1b3Sopenharmony_ci    pa_assert(state != STATE_TAKEN);
13053a5a1b3Sopenharmony_ci
13153a5a1b3Sopenharmony_ci    if (state == STATE_OWNING) {
13253a5a1b3Sopenharmony_ci
13353a5a1b3Sopenharmony_ci        pa_assert(lock_fd >= 0);
13453a5a1b3Sopenharmony_ci
13553a5a1b3Sopenharmony_ci        if (after_fork)
13653a5a1b3Sopenharmony_ci            pa_close(lock_fd);
13753a5a1b3Sopenharmony_ci        else {
13853a5a1b3Sopenharmony_ci            char *lf;
13953a5a1b3Sopenharmony_ci
14053a5a1b3Sopenharmony_ci            if (!(lf = pa_runtime_path(AUTOSPAWN_LOCK)))
14153a5a1b3Sopenharmony_ci                pa_log_warn(_("Cannot access autospawn lock."));
14253a5a1b3Sopenharmony_ci
14353a5a1b3Sopenharmony_ci            pa_unlock_lockfile(lf, lock_fd);
14453a5a1b3Sopenharmony_ci            pa_xfree(lf);
14553a5a1b3Sopenharmony_ci        }
14653a5a1b3Sopenharmony_ci    }
14753a5a1b3Sopenharmony_ci
14853a5a1b3Sopenharmony_ci    lock_fd = -1;
14953a5a1b3Sopenharmony_ci    state = STATE_IDLE;
15053a5a1b3Sopenharmony_ci
15153a5a1b3Sopenharmony_ci    pa_mutex_unlock(lock_fd_mutex);
15253a5a1b3Sopenharmony_ci
15353a5a1b3Sopenharmony_ci    pa_mutex_free(lock_fd_mutex);
15453a5a1b3Sopenharmony_ci    lock_fd_mutex = NULL;
15553a5a1b3Sopenharmony_ci
15653a5a1b3Sopenharmony_ci    pa_close(pipe_fd[0]);
15753a5a1b3Sopenharmony_ci    pa_close(pipe_fd[1]);
15853a5a1b3Sopenharmony_ci    pipe_fd[0] = pipe_fd[1] = -1;
15953a5a1b3Sopenharmony_ci}
16053a5a1b3Sopenharmony_ci
16153a5a1b3Sopenharmony_cistatic void ping(void) {
16253a5a1b3Sopenharmony_ci    ssize_t s;
16353a5a1b3Sopenharmony_ci
16453a5a1b3Sopenharmony_ci    pa_assert(pipe_fd[1] >= 0);
16553a5a1b3Sopenharmony_ci
16653a5a1b3Sopenharmony_ci    for (;;) {
16753a5a1b3Sopenharmony_ci        char x = 'x';
16853a5a1b3Sopenharmony_ci
16953a5a1b3Sopenharmony_ci        if ((s = pa_write(pipe_fd[1], &x, 1, NULL)) == 1)
17053a5a1b3Sopenharmony_ci            break;
17153a5a1b3Sopenharmony_ci
17253a5a1b3Sopenharmony_ci        pa_assert(s < 0);
17353a5a1b3Sopenharmony_ci
17453a5a1b3Sopenharmony_ci        if (errno == EAGAIN)
17553a5a1b3Sopenharmony_ci            break;
17653a5a1b3Sopenharmony_ci
17753a5a1b3Sopenharmony_ci        pa_assert(errno == EINTR);
17853a5a1b3Sopenharmony_ci    }
17953a5a1b3Sopenharmony_ci}
18053a5a1b3Sopenharmony_ci
18153a5a1b3Sopenharmony_cistatic void wait_for_ping(void) {
18253a5a1b3Sopenharmony_ci    ssize_t s;
18353a5a1b3Sopenharmony_ci    char x;
18453a5a1b3Sopenharmony_ci    struct pollfd pfd;
18553a5a1b3Sopenharmony_ci    int k;
18653a5a1b3Sopenharmony_ci
18753a5a1b3Sopenharmony_ci    pa_assert(pipe_fd[0] >= 0);
18853a5a1b3Sopenharmony_ci
18953a5a1b3Sopenharmony_ci    memset(&pfd, 0, sizeof(pfd));
19053a5a1b3Sopenharmony_ci    pfd.fd = pipe_fd[0];
19153a5a1b3Sopenharmony_ci    pfd.events = POLLIN;
19253a5a1b3Sopenharmony_ci
19353a5a1b3Sopenharmony_ci    if ((k = pa_poll(&pfd, 1, -1)) != 1) {
19453a5a1b3Sopenharmony_ci        pa_assert(k < 0);
19553a5a1b3Sopenharmony_ci        pa_assert(errno == EINTR);
19653a5a1b3Sopenharmony_ci    } else if ((s = pa_read(pipe_fd[0], &x, 1, NULL)) != 1) {
19753a5a1b3Sopenharmony_ci        pa_assert(s < 0);
19853a5a1b3Sopenharmony_ci        pa_assert(errno == EAGAIN);
19953a5a1b3Sopenharmony_ci    }
20053a5a1b3Sopenharmony_ci}
20153a5a1b3Sopenharmony_ci
20253a5a1b3Sopenharmony_cistatic void empty_pipe(void) {
20353a5a1b3Sopenharmony_ci    char x[16];
20453a5a1b3Sopenharmony_ci    ssize_t s;
20553a5a1b3Sopenharmony_ci
20653a5a1b3Sopenharmony_ci    pa_assert(pipe_fd[0] >= 0);
20753a5a1b3Sopenharmony_ci
20853a5a1b3Sopenharmony_ci    if ((s = pa_read(pipe_fd[0], &x, sizeof(x), NULL)) < 1) {
20953a5a1b3Sopenharmony_ci        pa_assert(s < 0);
21053a5a1b3Sopenharmony_ci        pa_assert(errno == EAGAIN);
21153a5a1b3Sopenharmony_ci    }
21253a5a1b3Sopenharmony_ci}
21353a5a1b3Sopenharmony_ci
21453a5a1b3Sopenharmony_cistatic void thread_func(void *u) {
21553a5a1b3Sopenharmony_ci    int fd;
21653a5a1b3Sopenharmony_ci    char *lf;
21753a5a1b3Sopenharmony_ci
21853a5a1b3Sopenharmony_ci#ifdef HAVE_PTHREAD
21953a5a1b3Sopenharmony_ci    sigset_t fullset;
22053a5a1b3Sopenharmony_ci
22153a5a1b3Sopenharmony_ci    /* No signals in this thread please */
22253a5a1b3Sopenharmony_ci    sigfillset(&fullset);
22353a5a1b3Sopenharmony_ci    pthread_sigmask(SIG_BLOCK, &fullset, NULL);
22453a5a1b3Sopenharmony_ci#endif
22553a5a1b3Sopenharmony_ci
22653a5a1b3Sopenharmony_ci    if (!(lf = pa_runtime_path(AUTOSPAWN_LOCK))) {
22753a5a1b3Sopenharmony_ci        pa_log_warn(_("Cannot access autospawn lock."));
22853a5a1b3Sopenharmony_ci        goto fail;
22953a5a1b3Sopenharmony_ci    }
23053a5a1b3Sopenharmony_ci
23153a5a1b3Sopenharmony_ci    if ((fd = pa_lock_lockfile(lf)) < 0)
23253a5a1b3Sopenharmony_ci        goto fail;
23353a5a1b3Sopenharmony_ci
23453a5a1b3Sopenharmony_ci    pa_mutex_lock(lock_fd_mutex);
23553a5a1b3Sopenharmony_ci    pa_assert(state == STATE_IDLE);
23653a5a1b3Sopenharmony_ci    lock_fd = fd;
23753a5a1b3Sopenharmony_ci    state = STATE_OWNING;
23853a5a1b3Sopenharmony_ci    pa_mutex_unlock(lock_fd_mutex);
23953a5a1b3Sopenharmony_ci
24053a5a1b3Sopenharmony_ci    goto finish;
24153a5a1b3Sopenharmony_ci
24253a5a1b3Sopenharmony_cifail:
24353a5a1b3Sopenharmony_ci    pa_mutex_lock(lock_fd_mutex);
24453a5a1b3Sopenharmony_ci    pa_assert(state == STATE_IDLE);
24553a5a1b3Sopenharmony_ci    state = STATE_FAILED;
24653a5a1b3Sopenharmony_ci    pa_mutex_unlock(lock_fd_mutex);
24753a5a1b3Sopenharmony_ci
24853a5a1b3Sopenharmony_cifinish:
24953a5a1b3Sopenharmony_ci    pa_xfree(lf);
25053a5a1b3Sopenharmony_ci
25153a5a1b3Sopenharmony_ci    ping();
25253a5a1b3Sopenharmony_ci}
25353a5a1b3Sopenharmony_ci
25453a5a1b3Sopenharmony_cistatic int start_thread(void) {
25553a5a1b3Sopenharmony_ci
25653a5a1b3Sopenharmony_ci    if (!thread)
25753a5a1b3Sopenharmony_ci        if (!(thread = pa_thread_new("autospawn", thread_func, NULL)))
25853a5a1b3Sopenharmony_ci            return -1;
25953a5a1b3Sopenharmony_ci
26053a5a1b3Sopenharmony_ci    return 0;
26153a5a1b3Sopenharmony_ci}
26253a5a1b3Sopenharmony_ci
26353a5a1b3Sopenharmony_cistatic void create_mutex(void) {
26453a5a1b3Sopenharmony_ci    PA_ONCE_BEGIN {
26553a5a1b3Sopenharmony_ci        mutex = pa_mutex_new(false, false);
26653a5a1b3Sopenharmony_ci    } PA_ONCE_END;
26753a5a1b3Sopenharmony_ci}
26853a5a1b3Sopenharmony_ci
26953a5a1b3Sopenharmony_cistatic void destroy_mutex(void) {
27053a5a1b3Sopenharmony_ci    if (mutex)
27153a5a1b3Sopenharmony_ci        pa_mutex_free(mutex);
27253a5a1b3Sopenharmony_ci}
27353a5a1b3Sopenharmony_ci
27453a5a1b3Sopenharmony_ciint pa_autospawn_lock_init(void) {
27553a5a1b3Sopenharmony_ci    int ret = -1;
27653a5a1b3Sopenharmony_ci
27753a5a1b3Sopenharmony_ci    create_mutex();
27853a5a1b3Sopenharmony_ci    pa_mutex_lock(mutex);
27953a5a1b3Sopenharmony_ci
28053a5a1b3Sopenharmony_ci    if (ref() < 0)
28153a5a1b3Sopenharmony_ci        ret = -1;
28253a5a1b3Sopenharmony_ci    else
28353a5a1b3Sopenharmony_ci        ret = pipe_fd[0];
28453a5a1b3Sopenharmony_ci
28553a5a1b3Sopenharmony_ci    pa_mutex_unlock(mutex);
28653a5a1b3Sopenharmony_ci
28753a5a1b3Sopenharmony_ci    return ret;
28853a5a1b3Sopenharmony_ci}
28953a5a1b3Sopenharmony_ci
29053a5a1b3Sopenharmony_ciint pa_autospawn_lock_acquire(bool block) {
29153a5a1b3Sopenharmony_ci    int ret = -1;
29253a5a1b3Sopenharmony_ci
29353a5a1b3Sopenharmony_ci    create_mutex();
29453a5a1b3Sopenharmony_ci    pa_mutex_lock(mutex);
29553a5a1b3Sopenharmony_ci    pa_assert(n_ref >= 1);
29653a5a1b3Sopenharmony_ci
29753a5a1b3Sopenharmony_ci    pa_mutex_lock(lock_fd_mutex);
29853a5a1b3Sopenharmony_ci
29953a5a1b3Sopenharmony_ci    for (;;) {
30053a5a1b3Sopenharmony_ci
30153a5a1b3Sopenharmony_ci        empty_pipe();
30253a5a1b3Sopenharmony_ci
30353a5a1b3Sopenharmony_ci        if (state == STATE_OWNING) {
30453a5a1b3Sopenharmony_ci            state = STATE_TAKEN;
30553a5a1b3Sopenharmony_ci            ret = 1;
30653a5a1b3Sopenharmony_ci            break;
30753a5a1b3Sopenharmony_ci        }
30853a5a1b3Sopenharmony_ci
30953a5a1b3Sopenharmony_ci        if (state == STATE_FAILED) {
31053a5a1b3Sopenharmony_ci            ret = -1;
31153a5a1b3Sopenharmony_ci            break;
31253a5a1b3Sopenharmony_ci        }
31353a5a1b3Sopenharmony_ci
31453a5a1b3Sopenharmony_ci        if (state == STATE_IDLE)
31553a5a1b3Sopenharmony_ci            if (start_thread() < 0)
31653a5a1b3Sopenharmony_ci                break;
31753a5a1b3Sopenharmony_ci
31853a5a1b3Sopenharmony_ci        if (!block) {
31953a5a1b3Sopenharmony_ci            ret = 0;
32053a5a1b3Sopenharmony_ci            break;
32153a5a1b3Sopenharmony_ci        }
32253a5a1b3Sopenharmony_ci
32353a5a1b3Sopenharmony_ci        pa_mutex_unlock(lock_fd_mutex);
32453a5a1b3Sopenharmony_ci        pa_mutex_unlock(mutex);
32553a5a1b3Sopenharmony_ci
32653a5a1b3Sopenharmony_ci        wait_for_ping();
32753a5a1b3Sopenharmony_ci
32853a5a1b3Sopenharmony_ci        pa_mutex_lock(mutex);
32953a5a1b3Sopenharmony_ci        pa_mutex_lock(lock_fd_mutex);
33053a5a1b3Sopenharmony_ci    }
33153a5a1b3Sopenharmony_ci
33253a5a1b3Sopenharmony_ci    pa_mutex_unlock(lock_fd_mutex);
33353a5a1b3Sopenharmony_ci
33453a5a1b3Sopenharmony_ci    pa_mutex_unlock(mutex);
33553a5a1b3Sopenharmony_ci
33653a5a1b3Sopenharmony_ci    return ret;
33753a5a1b3Sopenharmony_ci}
33853a5a1b3Sopenharmony_ci
33953a5a1b3Sopenharmony_civoid pa_autospawn_lock_release(void) {
34053a5a1b3Sopenharmony_ci
34153a5a1b3Sopenharmony_ci    create_mutex();
34253a5a1b3Sopenharmony_ci    pa_mutex_lock(mutex);
34353a5a1b3Sopenharmony_ci    pa_assert(n_ref >= 1);
34453a5a1b3Sopenharmony_ci
34553a5a1b3Sopenharmony_ci    pa_assert(state == STATE_TAKEN);
34653a5a1b3Sopenharmony_ci    state = STATE_OWNING;
34753a5a1b3Sopenharmony_ci
34853a5a1b3Sopenharmony_ci    ping();
34953a5a1b3Sopenharmony_ci
35053a5a1b3Sopenharmony_ci    pa_mutex_unlock(mutex);
35153a5a1b3Sopenharmony_ci}
35253a5a1b3Sopenharmony_ci
35353a5a1b3Sopenharmony_civoid pa_autospawn_lock_done(bool after_fork) {
35453a5a1b3Sopenharmony_ci
35553a5a1b3Sopenharmony_ci    create_mutex();
35653a5a1b3Sopenharmony_ci    pa_mutex_lock(mutex);
35753a5a1b3Sopenharmony_ci    pa_assert(n_ref >= 1);
35853a5a1b3Sopenharmony_ci
35953a5a1b3Sopenharmony_ci    unref(after_fork);
36053a5a1b3Sopenharmony_ci
36153a5a1b3Sopenharmony_ci    pa_mutex_unlock(mutex);
36253a5a1b3Sopenharmony_ci}
363