xref: /third_party/pulseaudio/src/pulse/util.c (revision 53a5a1b3)
153a5a1b3Sopenharmony_ci/***
253a5a1b3Sopenharmony_ci  This file is part of PulseAudio.
353a5a1b3Sopenharmony_ci
453a5a1b3Sopenharmony_ci  Copyright 2004-2006 Lennart Poettering
553a5a1b3Sopenharmony_ci  Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
653a5a1b3Sopenharmony_ci
753a5a1b3Sopenharmony_ci  PulseAudio is free software; you can redistribute it and/or modify
853a5a1b3Sopenharmony_ci  it under the terms of the GNU Lesser General Public License as
953a5a1b3Sopenharmony_ci  published by the Free Software Foundation; either version 2.1 of the
1053a5a1b3Sopenharmony_ci  License, or (at your option) any later version.
1153a5a1b3Sopenharmony_ci
1253a5a1b3Sopenharmony_ci  PulseAudio is distributed in the hope that it will be useful, but
1353a5a1b3Sopenharmony_ci  WITHOUT ANY WARRANTY; without even the implied warranty of
1453a5a1b3Sopenharmony_ci  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1553a5a1b3Sopenharmony_ci  Lesser General Public License for more details.
1653a5a1b3Sopenharmony_ci
1753a5a1b3Sopenharmony_ci  You should have received a copy of the GNU Lesser General Public
1853a5a1b3Sopenharmony_ci  License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
1953a5a1b3Sopenharmony_ci***/
2053a5a1b3Sopenharmony_ci
2153a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H
2253a5a1b3Sopenharmony_ci#include <config.h>
2353a5a1b3Sopenharmony_ci#endif
2453a5a1b3Sopenharmony_ci
2553a5a1b3Sopenharmony_ci#include <errno.h>
2653a5a1b3Sopenharmony_ci#include <limits.h>
2753a5a1b3Sopenharmony_ci#include <stdio.h>
2853a5a1b3Sopenharmony_ci#include <stdlib.h>
2953a5a1b3Sopenharmony_ci#include <string.h>
3053a5a1b3Sopenharmony_ci#include <time.h>
3153a5a1b3Sopenharmony_ci#include <unistd.h>
3253a5a1b3Sopenharmony_ci#include <sys/types.h>
3353a5a1b3Sopenharmony_ci
3453a5a1b3Sopenharmony_ci#ifdef HAVE_PWD_H
3553a5a1b3Sopenharmony_ci#include <pwd.h>
3653a5a1b3Sopenharmony_ci#endif
3753a5a1b3Sopenharmony_ci
3853a5a1b3Sopenharmony_ci#ifdef HAVE_NETDB_H
3953a5a1b3Sopenharmony_ci#include <netdb.h>
4053a5a1b3Sopenharmony_ci#endif
4153a5a1b3Sopenharmony_ci
4253a5a1b3Sopenharmony_ci#ifdef HAVE_WINDOWS_H
4353a5a1b3Sopenharmony_ci#include <windows.h>
4453a5a1b3Sopenharmony_ci#endif
4553a5a1b3Sopenharmony_ci
4653a5a1b3Sopenharmony_ci#ifdef HAVE_SYS_PRCTL_H
4753a5a1b3Sopenharmony_ci#include <sys/prctl.h>
4853a5a1b3Sopenharmony_ci#endif
4953a5a1b3Sopenharmony_ci
5053a5a1b3Sopenharmony_ci#ifdef OS_IS_DARWIN
5153a5a1b3Sopenharmony_ci#include <libgen.h>
5253a5a1b3Sopenharmony_ci#include <sys/sysctl.h>
5353a5a1b3Sopenharmony_ci#endif
5453a5a1b3Sopenharmony_ci
5553a5a1b3Sopenharmony_ci#include <pulse/xmalloc.h>
5653a5a1b3Sopenharmony_ci#include <pulse/timeval.h>
5753a5a1b3Sopenharmony_ci
5853a5a1b3Sopenharmony_ci#include <pulsecore/socket.h>
5953a5a1b3Sopenharmony_ci#include <pulsecore/core-error.h>
6053a5a1b3Sopenharmony_ci#include <pulsecore/core-util.h>
6153a5a1b3Sopenharmony_ci#include <pulsecore/macro.h>
6253a5a1b3Sopenharmony_ci#include <pulsecore/usergroup.h>
6353a5a1b3Sopenharmony_ci
6453a5a1b3Sopenharmony_ci#include "util.h"
6553a5a1b3Sopenharmony_ci
6653a5a1b3Sopenharmony_ci#if defined(HAVE_DLADDR) && defined(PA_GCC_WEAKREF)
6753a5a1b3Sopenharmony_ci#ifndef _GNU_SOURCE
6853a5a1b3Sopenharmony_ci#define _GNU_SOURCE 1
6953a5a1b3Sopenharmony_ci#endif
7053a5a1b3Sopenharmony_ci#include <dlfcn.h>
7153a5a1b3Sopenharmony_ci
7253a5a1b3Sopenharmony_cistatic int _main() PA_GCC_WEAKREF(main);
7353a5a1b3Sopenharmony_ci#endif
7453a5a1b3Sopenharmony_ci
7553a5a1b3Sopenharmony_ci#ifdef HAVE_PTHREAD
7653a5a1b3Sopenharmony_ci#include <pthread.h>
7753a5a1b3Sopenharmony_ci#endif
7853a5a1b3Sopenharmony_ci
7953a5a1b3Sopenharmony_ci#ifdef HAVE_SCHED_H
8053a5a1b3Sopenharmony_ci#include <sched.h>
8153a5a1b3Sopenharmony_ci
8253a5a1b3Sopenharmony_ci#if defined(__linux__) && !defined(SCHED_RESET_ON_FORK)
8353a5a1b3Sopenharmony_ci#define SCHED_RESET_ON_FORK 0x40000000
8453a5a1b3Sopenharmony_ci#endif
8553a5a1b3Sopenharmony_ci#endif
8653a5a1b3Sopenharmony_ci
8753a5a1b3Sopenharmony_ci#ifdef __APPLE__
8853a5a1b3Sopenharmony_ci#include <mach/mach_init.h>
8953a5a1b3Sopenharmony_ci#include <mach/thread_act.h>
9053a5a1b3Sopenharmony_ci#include <mach/thread_policy.h>
9153a5a1b3Sopenharmony_ci#include <sys/sysctl.h>
9253a5a1b3Sopenharmony_ci#endif
9353a5a1b3Sopenharmony_ci
9453a5a1b3Sopenharmony_ci#ifdef __FreeBSD__
9553a5a1b3Sopenharmony_ci#include <sys/sysctl.h>
9653a5a1b3Sopenharmony_ci#endif
9753a5a1b3Sopenharmony_ci
9853a5a1b3Sopenharmony_ci#ifdef HAVE_DBUS
9953a5a1b3Sopenharmony_ci#include <pulsecore/rtkit.h>
10053a5a1b3Sopenharmony_ci#endif
10153a5a1b3Sopenharmony_ci
10253a5a1b3Sopenharmony_cichar *pa_get_user_name(char *s, size_t l) {
10353a5a1b3Sopenharmony_ci    const char *p;
10453a5a1b3Sopenharmony_ci    char *name = NULL;
10553a5a1b3Sopenharmony_ci#ifdef OS_IS_WIN32
10653a5a1b3Sopenharmony_ci    char buf[1024];
10753a5a1b3Sopenharmony_ci#endif
10853a5a1b3Sopenharmony_ci
10953a5a1b3Sopenharmony_ci#ifdef HAVE_PWD_H
11053a5a1b3Sopenharmony_ci    struct passwd *r;
11153a5a1b3Sopenharmony_ci#endif
11253a5a1b3Sopenharmony_ci
11353a5a1b3Sopenharmony_ci    pa_assert(s);
11453a5a1b3Sopenharmony_ci    pa_assert(l > 0);
11553a5a1b3Sopenharmony_ci
11653a5a1b3Sopenharmony_ci    p = NULL;
11753a5a1b3Sopenharmony_ci#ifdef HAVE_GETUID
11853a5a1b3Sopenharmony_ci    p = getuid() == 0 ? "root" : NULL;
11953a5a1b3Sopenharmony_ci#endif
12053a5a1b3Sopenharmony_ci    if (!p) p = getenv("USER");
12153a5a1b3Sopenharmony_ci    if (!p) p = getenv("LOGNAME");
12253a5a1b3Sopenharmony_ci    if (!p) p = getenv("USERNAME");
12353a5a1b3Sopenharmony_ci
12453a5a1b3Sopenharmony_ci    if (p) {
12553a5a1b3Sopenharmony_ci        name = pa_strlcpy(s, p, l);
12653a5a1b3Sopenharmony_ci    } else {
12753a5a1b3Sopenharmony_ci#ifdef HAVE_PWD_H
12853a5a1b3Sopenharmony_ci
12953a5a1b3Sopenharmony_ci        if ((r = pa_getpwuid_malloc(getuid())) == NULL) {
13053a5a1b3Sopenharmony_ci            pa_snprintf(s, l, "%lu", (unsigned long) getuid());
13153a5a1b3Sopenharmony_ci            return s;
13253a5a1b3Sopenharmony_ci        }
13353a5a1b3Sopenharmony_ci
13453a5a1b3Sopenharmony_ci        name = pa_strlcpy(s, r->pw_name, l);
13553a5a1b3Sopenharmony_ci        pa_getpwuid_free(r);
13653a5a1b3Sopenharmony_ci
13753a5a1b3Sopenharmony_ci#elif defined(OS_IS_WIN32) /* HAVE_PWD_H */
13853a5a1b3Sopenharmony_ci        DWORD size = sizeof(buf);
13953a5a1b3Sopenharmony_ci
14053a5a1b3Sopenharmony_ci        if (!GetUserName(buf, &size)) {
14153a5a1b3Sopenharmony_ci            errno = ENOENT;
14253a5a1b3Sopenharmony_ci            return NULL;
14353a5a1b3Sopenharmony_ci        }
14453a5a1b3Sopenharmony_ci
14553a5a1b3Sopenharmony_ci        name = pa_strlcpy(s, buf, l);
14653a5a1b3Sopenharmony_ci
14753a5a1b3Sopenharmony_ci#else /* HAVE_PWD_H */
14853a5a1b3Sopenharmony_ci
14953a5a1b3Sopenharmony_ci        return NULL;
15053a5a1b3Sopenharmony_ci#endif /* HAVE_PWD_H */
15153a5a1b3Sopenharmony_ci    }
15253a5a1b3Sopenharmony_ci
15353a5a1b3Sopenharmony_ci    return name;
15453a5a1b3Sopenharmony_ci}
15553a5a1b3Sopenharmony_ci
15653a5a1b3Sopenharmony_cichar *pa_get_host_name(char *s, size_t l) {
15753a5a1b3Sopenharmony_ci
15853a5a1b3Sopenharmony_ci    pa_assert(s);
15953a5a1b3Sopenharmony_ci    pa_assert(l > 0);
16053a5a1b3Sopenharmony_ci
16153a5a1b3Sopenharmony_ci    if (gethostname(s, l) < 0)
16253a5a1b3Sopenharmony_ci        return NULL;
16353a5a1b3Sopenharmony_ci
16453a5a1b3Sopenharmony_ci    s[l-1] = 0;
16553a5a1b3Sopenharmony_ci    return s;
16653a5a1b3Sopenharmony_ci}
16753a5a1b3Sopenharmony_ci
16853a5a1b3Sopenharmony_cichar *pa_get_home_dir(char *s, size_t l) {
16953a5a1b3Sopenharmony_ci    char *e;
17053a5a1b3Sopenharmony_ci    char *dir;
17153a5a1b3Sopenharmony_ci#ifdef HAVE_PWD_H
17253a5a1b3Sopenharmony_ci    struct passwd *r;
17353a5a1b3Sopenharmony_ci#endif
17453a5a1b3Sopenharmony_ci
17553a5a1b3Sopenharmony_ci    pa_assert(s);
17653a5a1b3Sopenharmony_ci    pa_assert(l > 0);
17753a5a1b3Sopenharmony_ci
17853a5a1b3Sopenharmony_ci    if ((e = getenv("HOME"))) {
17953a5a1b3Sopenharmony_ci        dir = pa_strlcpy(s, e, l);
18053a5a1b3Sopenharmony_ci        goto finish;
18153a5a1b3Sopenharmony_ci    }
18253a5a1b3Sopenharmony_ci
18353a5a1b3Sopenharmony_ci    if ((e = getenv("USERPROFILE"))) {
18453a5a1b3Sopenharmony_ci        dir = pa_strlcpy(s, e, l);
18553a5a1b3Sopenharmony_ci        goto finish;
18653a5a1b3Sopenharmony_ci    }
18753a5a1b3Sopenharmony_ci
18853a5a1b3Sopenharmony_ci#ifdef HAVE_PWD_H
18953a5a1b3Sopenharmony_ci    errno = 0;
19053a5a1b3Sopenharmony_ci    if ((r = pa_getpwuid_malloc(getuid())) == NULL) {
19153a5a1b3Sopenharmony_ci        if (!errno)
19253a5a1b3Sopenharmony_ci            errno = ENOENT;
19353a5a1b3Sopenharmony_ci
19453a5a1b3Sopenharmony_ci        return NULL;
19553a5a1b3Sopenharmony_ci    }
19653a5a1b3Sopenharmony_ci
19753a5a1b3Sopenharmony_ci    dir = pa_strlcpy(s, r->pw_dir, l);
19853a5a1b3Sopenharmony_ci
19953a5a1b3Sopenharmony_ci    pa_getpwuid_free(r);
20053a5a1b3Sopenharmony_ci#endif /* HAVE_PWD_H */
20153a5a1b3Sopenharmony_ci
20253a5a1b3Sopenharmony_cifinish:
20353a5a1b3Sopenharmony_ci    if (!dir) {
20453a5a1b3Sopenharmony_ci        errno = ENOENT;
20553a5a1b3Sopenharmony_ci        return NULL;
20653a5a1b3Sopenharmony_ci    }
20753a5a1b3Sopenharmony_ci
20853a5a1b3Sopenharmony_ci    if (!pa_is_path_absolute(dir)) {
20953a5a1b3Sopenharmony_ci        pa_log("Failed to get the home directory, not an absolute path: %s", dir);
21053a5a1b3Sopenharmony_ci        errno = ENOENT;
21153a5a1b3Sopenharmony_ci        return NULL;
21253a5a1b3Sopenharmony_ci    }
21353a5a1b3Sopenharmony_ci
21453a5a1b3Sopenharmony_ci    return dir;
21553a5a1b3Sopenharmony_ci}
21653a5a1b3Sopenharmony_ci
21753a5a1b3Sopenharmony_cichar *pa_get_binary_name(char *s, size_t l) {
21853a5a1b3Sopenharmony_ci
21953a5a1b3Sopenharmony_ci    pa_assert(s);
22053a5a1b3Sopenharmony_ci    pa_assert(l > 0);
22153a5a1b3Sopenharmony_ci
22253a5a1b3Sopenharmony_ci#if defined(OS_IS_WIN32)
22353a5a1b3Sopenharmony_ci    {
22453a5a1b3Sopenharmony_ci        char path[PATH_MAX];
22553a5a1b3Sopenharmony_ci
22653a5a1b3Sopenharmony_ci        if (GetModuleFileName(NULL, path, PATH_MAX))
22753a5a1b3Sopenharmony_ci            return pa_strlcpy(s, pa_path_get_filename(path), l);
22853a5a1b3Sopenharmony_ci    }
22953a5a1b3Sopenharmony_ci#endif
23053a5a1b3Sopenharmony_ci
23153a5a1b3Sopenharmony_ci#if defined(__linux__) || (defined(__FreeBSD_kernel__) && !defined(__FreeBSD__)) || defined(__GNU__)
23253a5a1b3Sopenharmony_ci    {
23353a5a1b3Sopenharmony_ci        char *rp;
23453a5a1b3Sopenharmony_ci        /* This works on Linux and Debian/kFreeBSD */
23553a5a1b3Sopenharmony_ci
23653a5a1b3Sopenharmony_ci        if ((rp = pa_readlink("/proc/self/exe"))) {
23753a5a1b3Sopenharmony_ci            pa_strlcpy(s, pa_path_get_filename(rp), l);
23853a5a1b3Sopenharmony_ci            pa_xfree(rp);
23953a5a1b3Sopenharmony_ci            return s;
24053a5a1b3Sopenharmony_ci        }
24153a5a1b3Sopenharmony_ci    }
24253a5a1b3Sopenharmony_ci#endif
24353a5a1b3Sopenharmony_ci
24453a5a1b3Sopenharmony_ci#ifdef __FreeBSD__
24553a5a1b3Sopenharmony_ci    {
24653a5a1b3Sopenharmony_ci        char path[PATH_MAX + 1];
24753a5a1b3Sopenharmony_ci        size_t len = PATH_MAX;
24853a5a1b3Sopenharmony_ci        int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
24953a5a1b3Sopenharmony_ci
25053a5a1b3Sopenharmony_ci        if (sysctl(mib, 4, &path, &len, NULL, 0) == 0) {
25153a5a1b3Sopenharmony_ci            pa_strlcpy(s, pa_path_get_filename(path), l);
25253a5a1b3Sopenharmony_ci            return s;
25353a5a1b3Sopenharmony_ci        }
25453a5a1b3Sopenharmony_ci    }
25553a5a1b3Sopenharmony_ci#endif
25653a5a1b3Sopenharmony_ci
25753a5a1b3Sopenharmony_ci#if defined(HAVE_DLADDR) && defined(PA_GCC_WEAKREF)
25853a5a1b3Sopenharmony_ci    {
25953a5a1b3Sopenharmony_ci        Dl_info info;
26053a5a1b3Sopenharmony_ci        if(_main) {
26153a5a1b3Sopenharmony_ci            int err = dladdr(&_main, &info);
26253a5a1b3Sopenharmony_ci            if (err != 0) {
26353a5a1b3Sopenharmony_ci                char *p = pa_realpath(info.dli_fname);
26453a5a1b3Sopenharmony_ci                if (p)
26553a5a1b3Sopenharmony_ci                    return p;
26653a5a1b3Sopenharmony_ci            }
26753a5a1b3Sopenharmony_ci        }
26853a5a1b3Sopenharmony_ci    }
26953a5a1b3Sopenharmony_ci#endif
27053a5a1b3Sopenharmony_ci
27153a5a1b3Sopenharmony_ci#if defined(HAVE_SYS_PRCTL_H) && defined(PR_GET_NAME)
27253a5a1b3Sopenharmony_ci    {
27353a5a1b3Sopenharmony_ci
27453a5a1b3Sopenharmony_ci        #ifndef TASK_COMM_LEN
27553a5a1b3Sopenharmony_ci        /* Actually defined in linux/sched.h */
27653a5a1b3Sopenharmony_ci        #define TASK_COMM_LEN 16
27753a5a1b3Sopenharmony_ci        #endif
27853a5a1b3Sopenharmony_ci
27953a5a1b3Sopenharmony_ci        char tcomm[TASK_COMM_LEN+1];
28053a5a1b3Sopenharmony_ci        memset(tcomm, 0, sizeof(tcomm));
28153a5a1b3Sopenharmony_ci
28253a5a1b3Sopenharmony_ci        /* This works on Linux only */
28353a5a1b3Sopenharmony_ci        if (prctl(PR_GET_NAME, (unsigned long) tcomm, 0, 0, 0) == 0)
28453a5a1b3Sopenharmony_ci            return pa_strlcpy(s, tcomm, l);
28553a5a1b3Sopenharmony_ci
28653a5a1b3Sopenharmony_ci    }
28753a5a1b3Sopenharmony_ci#endif
28853a5a1b3Sopenharmony_ci
28953a5a1b3Sopenharmony_ci#ifdef OS_IS_DARWIN
29053a5a1b3Sopenharmony_ci    {
29153a5a1b3Sopenharmony_ci        int mib[] = { CTL_KERN, KERN_PROCARGS, getpid(), 0 };
29253a5a1b3Sopenharmony_ci        size_t len, nmib = (sizeof(mib) / sizeof(mib[0])) - 1;
29353a5a1b3Sopenharmony_ci        char *buf;
29453a5a1b3Sopenharmony_ci
29553a5a1b3Sopenharmony_ci        sysctl(mib, nmib, NULL, &len, NULL, 0);
29653a5a1b3Sopenharmony_ci        buf = (char *) pa_xmalloc(len);
29753a5a1b3Sopenharmony_ci
29853a5a1b3Sopenharmony_ci        if (sysctl(mib, nmib, buf, &len, NULL, 0) == 0) {
29953a5a1b3Sopenharmony_ci            pa_strlcpy(s, basename(buf), l);
30053a5a1b3Sopenharmony_ci            pa_xfree(buf);
30153a5a1b3Sopenharmony_ci            return s;
30253a5a1b3Sopenharmony_ci        }
30353a5a1b3Sopenharmony_ci
30453a5a1b3Sopenharmony_ci        pa_xfree(buf);
30553a5a1b3Sopenharmony_ci
30653a5a1b3Sopenharmony_ci        /* fall thru */
30753a5a1b3Sopenharmony_ci    }
30853a5a1b3Sopenharmony_ci#endif /* OS_IS_DARWIN */
30953a5a1b3Sopenharmony_ci
31053a5a1b3Sopenharmony_ci    errno = ENOENT;
31153a5a1b3Sopenharmony_ci    return NULL;
31253a5a1b3Sopenharmony_ci}
31353a5a1b3Sopenharmony_ci
31453a5a1b3Sopenharmony_cichar *pa_path_get_filename(const char *p) {
31553a5a1b3Sopenharmony_ci    char *fn;
31653a5a1b3Sopenharmony_ci
31753a5a1b3Sopenharmony_ci    if (!p)
31853a5a1b3Sopenharmony_ci        return NULL;
31953a5a1b3Sopenharmony_ci
32053a5a1b3Sopenharmony_ci    if ((fn = strrchr(p, PA_PATH_SEP_CHAR)))
32153a5a1b3Sopenharmony_ci        return fn+1;
32253a5a1b3Sopenharmony_ci
32353a5a1b3Sopenharmony_ci    return (char*) p;
32453a5a1b3Sopenharmony_ci}
32553a5a1b3Sopenharmony_ci
32653a5a1b3Sopenharmony_cichar *pa_get_fqdn(char *s, size_t l) {
32753a5a1b3Sopenharmony_ci    char hn[256];
32853a5a1b3Sopenharmony_ci#ifdef HAVE_GETADDRINFO
32953a5a1b3Sopenharmony_ci    struct addrinfo *a = NULL, hints;
33053a5a1b3Sopenharmony_ci#endif
33153a5a1b3Sopenharmony_ci
33253a5a1b3Sopenharmony_ci    pa_assert(s);
33353a5a1b3Sopenharmony_ci    pa_assert(l > 0);
33453a5a1b3Sopenharmony_ci
33553a5a1b3Sopenharmony_ci    if (!pa_get_host_name(hn, sizeof(hn)))
33653a5a1b3Sopenharmony_ci        return NULL;
33753a5a1b3Sopenharmony_ci
33853a5a1b3Sopenharmony_ci#ifdef HAVE_GETADDRINFO
33953a5a1b3Sopenharmony_ci    memset(&hints, 0, sizeof(hints));
34053a5a1b3Sopenharmony_ci    hints.ai_family = AF_UNSPEC;
34153a5a1b3Sopenharmony_ci    hints.ai_flags = AI_CANONNAME;
34253a5a1b3Sopenharmony_ci
34353a5a1b3Sopenharmony_ci    if (getaddrinfo(hn, NULL, &hints, &a))
34453a5a1b3Sopenharmony_ci        return pa_strlcpy(s, hn, l);
34553a5a1b3Sopenharmony_ci
34653a5a1b3Sopenharmony_ci    if (!a->ai_canonname || !*a->ai_canonname) {
34753a5a1b3Sopenharmony_ci        freeaddrinfo(a);
34853a5a1b3Sopenharmony_ci        return pa_strlcpy(s, hn, l);
34953a5a1b3Sopenharmony_ci    }
35053a5a1b3Sopenharmony_ci
35153a5a1b3Sopenharmony_ci    pa_strlcpy(s, a->ai_canonname, l);
35253a5a1b3Sopenharmony_ci    freeaddrinfo(a);
35353a5a1b3Sopenharmony_ci    return s;
35453a5a1b3Sopenharmony_ci#else
35553a5a1b3Sopenharmony_ci    return pa_strlcpy(s, hn, l);
35653a5a1b3Sopenharmony_ci#endif
35753a5a1b3Sopenharmony_ci}
35853a5a1b3Sopenharmony_ci
35953a5a1b3Sopenharmony_ciint pa_msleep(unsigned long t) {
36053a5a1b3Sopenharmony_ci#ifdef OS_IS_WIN32
36153a5a1b3Sopenharmony_ci    Sleep(t);
36253a5a1b3Sopenharmony_ci    return 0;
36353a5a1b3Sopenharmony_ci#elif defined(HAVE_NANOSLEEP)
36453a5a1b3Sopenharmony_ci    struct timespec ts;
36553a5a1b3Sopenharmony_ci
36653a5a1b3Sopenharmony_ci    ts.tv_sec = (time_t) (t / PA_MSEC_PER_SEC);
36753a5a1b3Sopenharmony_ci    ts.tv_nsec = (long) ((t % PA_MSEC_PER_SEC) * PA_NSEC_PER_MSEC);
36853a5a1b3Sopenharmony_ci
36953a5a1b3Sopenharmony_ci    return nanosleep(&ts, NULL);
37053a5a1b3Sopenharmony_ci#else
37153a5a1b3Sopenharmony_ci#error "Platform lacks a sleep function."
37253a5a1b3Sopenharmony_ci#endif
37353a5a1b3Sopenharmony_ci}
37453a5a1b3Sopenharmony_ci
37553a5a1b3Sopenharmony_ci#ifdef _POSIX_PRIORITY_SCHEDULING
37653a5a1b3Sopenharmony_cistatic int set_scheduler(int rtprio) {
37753a5a1b3Sopenharmony_ci#ifdef HAVE_SCHED_H
37853a5a1b3Sopenharmony_ci    struct sched_param sp;
37953a5a1b3Sopenharmony_ci#ifdef HAVE_DBUS
38053a5a1b3Sopenharmony_ci    int r;
38153a5a1b3Sopenharmony_ci    long long rttime;
38253a5a1b3Sopenharmony_ci#ifdef RLIMIT_RTTIME
38353a5a1b3Sopenharmony_ci    struct rlimit rl;
38453a5a1b3Sopenharmony_ci#endif
38553a5a1b3Sopenharmony_ci    DBusError error;
38653a5a1b3Sopenharmony_ci    DBusConnection *bus;
38753a5a1b3Sopenharmony_ci
38853a5a1b3Sopenharmony_ci    dbus_error_init(&error);
38953a5a1b3Sopenharmony_ci#endif
39053a5a1b3Sopenharmony_ci
39153a5a1b3Sopenharmony_ci    pa_zero(sp);
39253a5a1b3Sopenharmony_ci    sp.sched_priority = rtprio;
39353a5a1b3Sopenharmony_ci
39453a5a1b3Sopenharmony_ci#ifdef SCHED_RESET_ON_FORK
39553a5a1b3Sopenharmony_ci    if (pthread_setschedparam(pthread_self(), SCHED_RR|SCHED_RESET_ON_FORK, &sp) == 0) {
39653a5a1b3Sopenharmony_ci        pa_log_debug("SCHED_RR|SCHED_RESET_ON_FORK worked.");
39753a5a1b3Sopenharmony_ci        return 0;
39853a5a1b3Sopenharmony_ci    }
39953a5a1b3Sopenharmony_ci#endif
40053a5a1b3Sopenharmony_ci
40153a5a1b3Sopenharmony_ci    if (pthread_setschedparam(pthread_self(), SCHED_RR, &sp) == 0) {
40253a5a1b3Sopenharmony_ci        pa_log_debug("SCHED_RR worked.");
40353a5a1b3Sopenharmony_ci        return 0;
40453a5a1b3Sopenharmony_ci    }
40553a5a1b3Sopenharmony_ci#endif  /* HAVE_SCHED_H */
40653a5a1b3Sopenharmony_ci
40753a5a1b3Sopenharmony_ci#ifdef HAVE_DBUS
40853a5a1b3Sopenharmony_ci    /* Try to talk to RealtimeKit */
40953a5a1b3Sopenharmony_ci
41053a5a1b3Sopenharmony_ci    if (!(bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error))) {
41153a5a1b3Sopenharmony_ci        pa_log("Failed to connect to system bus: %s", error.message);
41253a5a1b3Sopenharmony_ci        dbus_error_free(&error);
41353a5a1b3Sopenharmony_ci        errno = -EIO;
41453a5a1b3Sopenharmony_ci        return -1;
41553a5a1b3Sopenharmony_ci    }
41653a5a1b3Sopenharmony_ci
41753a5a1b3Sopenharmony_ci    /* We need to disable exit on disconnect because otherwise
41853a5a1b3Sopenharmony_ci     * dbus_shutdown will kill us. See
41953a5a1b3Sopenharmony_ci     * https://bugs.freedesktop.org/show_bug.cgi?id=16924 */
42053a5a1b3Sopenharmony_ci    dbus_connection_set_exit_on_disconnect(bus, FALSE);
42153a5a1b3Sopenharmony_ci
42253a5a1b3Sopenharmony_ci    rttime = rtkit_get_rttime_usec_max(bus);
42353a5a1b3Sopenharmony_ci    if (rttime >= 0) {
42453a5a1b3Sopenharmony_ci#ifdef RLIMIT_RTTIME
42553a5a1b3Sopenharmony_ci        r = getrlimit(RLIMIT_RTTIME, &rl);
42653a5a1b3Sopenharmony_ci
42753a5a1b3Sopenharmony_ci        if (r >= 0 && (long long) rl.rlim_max > rttime) {
42853a5a1b3Sopenharmony_ci            pa_log_info("Clamping rlimit-rttime to %lld for RealtimeKit", rttime);
42953a5a1b3Sopenharmony_ci            rl.rlim_cur = rl.rlim_max = rttime;
43053a5a1b3Sopenharmony_ci            r = setrlimit(RLIMIT_RTTIME, &rl);
43153a5a1b3Sopenharmony_ci
43253a5a1b3Sopenharmony_ci            if (r < 0)
43353a5a1b3Sopenharmony_ci                pa_log("setrlimit() failed: %s", pa_cstrerror(errno));
43453a5a1b3Sopenharmony_ci        }
43553a5a1b3Sopenharmony_ci#endif
43653a5a1b3Sopenharmony_ci        r = rtkit_make_realtime(bus, 0, rtprio);
43753a5a1b3Sopenharmony_ci        dbus_connection_close(bus);
43853a5a1b3Sopenharmony_ci        dbus_connection_unref(bus);
43953a5a1b3Sopenharmony_ci
44053a5a1b3Sopenharmony_ci        if (r >= 0) {
44153a5a1b3Sopenharmony_ci            pa_log_debug("RealtimeKit worked.");
44253a5a1b3Sopenharmony_ci            return 0;
44353a5a1b3Sopenharmony_ci        }
44453a5a1b3Sopenharmony_ci
44553a5a1b3Sopenharmony_ci        errno = -r;
44653a5a1b3Sopenharmony_ci    } else {
44753a5a1b3Sopenharmony_ci        dbus_connection_close(bus);
44853a5a1b3Sopenharmony_ci        dbus_connection_unref(bus);
44953a5a1b3Sopenharmony_ci        errno = -rttime;
45053a5a1b3Sopenharmony_ci    }
45153a5a1b3Sopenharmony_ci
45253a5a1b3Sopenharmony_ci#else
45353a5a1b3Sopenharmony_ci    errno = 0;
45453a5a1b3Sopenharmony_ci#endif
45553a5a1b3Sopenharmony_ci
45653a5a1b3Sopenharmony_ci    return -1;
45753a5a1b3Sopenharmony_ci}
45853a5a1b3Sopenharmony_ci#endif
45953a5a1b3Sopenharmony_ci
46053a5a1b3Sopenharmony_ci/* Make the current thread a realtime thread, and acquire the highest
46153a5a1b3Sopenharmony_ci * rtprio we can get that is less or equal the specified parameter. If
46253a5a1b3Sopenharmony_ci * the thread is already realtime, don't do anything. */
46353a5a1b3Sopenharmony_ciint pa_thread_make_realtime(int rtprio) {
46453a5a1b3Sopenharmony_ci
46553a5a1b3Sopenharmony_ci#if defined(OS_IS_DARWIN)
46653a5a1b3Sopenharmony_ci    struct thread_time_constraint_policy ttcpolicy;
46753a5a1b3Sopenharmony_ci    uint64_t freq = 0;
46853a5a1b3Sopenharmony_ci    size_t size = sizeof(freq);
46953a5a1b3Sopenharmony_ci    int ret;
47053a5a1b3Sopenharmony_ci
47153a5a1b3Sopenharmony_ci    ret = sysctlbyname("hw.cpufrequency", &freq, &size, NULL, 0);
47253a5a1b3Sopenharmony_ci    if (ret < 0) {
47353a5a1b3Sopenharmony_ci        pa_log_info("Unable to read CPU frequency, acquisition of real-time scheduling failed.");
47453a5a1b3Sopenharmony_ci        return -1;
47553a5a1b3Sopenharmony_ci    }
47653a5a1b3Sopenharmony_ci
47753a5a1b3Sopenharmony_ci    pa_log_debug("sysctl for hw.cpufrequency: %llu", freq);
47853a5a1b3Sopenharmony_ci
47953a5a1b3Sopenharmony_ci    /* See http://developer.apple.com/library/mac/#documentation/Darwin/Conceptual/KernelProgramming/scheduler/scheduler.html */
48053a5a1b3Sopenharmony_ci    ttcpolicy.period = freq / 160;
48153a5a1b3Sopenharmony_ci    ttcpolicy.computation = freq / 3300;
48253a5a1b3Sopenharmony_ci    ttcpolicy.constraint = freq / 2200;
48353a5a1b3Sopenharmony_ci    ttcpolicy.preemptible = 1;
48453a5a1b3Sopenharmony_ci
48553a5a1b3Sopenharmony_ci    ret = thread_policy_set(mach_thread_self(),
48653a5a1b3Sopenharmony_ci                            THREAD_TIME_CONSTRAINT_POLICY,
48753a5a1b3Sopenharmony_ci                            (thread_policy_t) &ttcpolicy,
48853a5a1b3Sopenharmony_ci                            THREAD_TIME_CONSTRAINT_POLICY_COUNT);
48953a5a1b3Sopenharmony_ci    if (ret) {
49053a5a1b3Sopenharmony_ci        pa_log_info("Unable to set real-time thread priority (%08x).", ret);
49153a5a1b3Sopenharmony_ci        return -1;
49253a5a1b3Sopenharmony_ci    }
49353a5a1b3Sopenharmony_ci
49453a5a1b3Sopenharmony_ci    pa_log_info("Successfully acquired real-time thread priority.");
49553a5a1b3Sopenharmony_ci    return 0;
49653a5a1b3Sopenharmony_ci
49753a5a1b3Sopenharmony_ci#elif defined(_POSIX_PRIORITY_SCHEDULING)
49853a5a1b3Sopenharmony_ci    int p;
49953a5a1b3Sopenharmony_ci
50053a5a1b3Sopenharmony_ci    if (set_scheduler(rtprio) >= 0) {
50153a5a1b3Sopenharmony_ci        pa_log_info("Successfully enabled SCHED_RR scheduling for thread, with priority %i.", rtprio);
50253a5a1b3Sopenharmony_ci        return 0;
50353a5a1b3Sopenharmony_ci    }
50453a5a1b3Sopenharmony_ci
50553a5a1b3Sopenharmony_ci    for (p = rtprio-1; p >= 1; p--)
50653a5a1b3Sopenharmony_ci        if (set_scheduler(p) >= 0) {
50753a5a1b3Sopenharmony_ci            pa_log_info("Successfully enabled SCHED_RR scheduling for thread, with priority %i, which is lower than the requested %i.", p, rtprio);
50853a5a1b3Sopenharmony_ci            return 0;
50953a5a1b3Sopenharmony_ci        }
51053a5a1b3Sopenharmony_ci#elif defined(OS_IS_WIN32)
51153a5a1b3Sopenharmony_ci    /* Windows only allows realtime scheduling to be set on a per process basis.
51253a5a1b3Sopenharmony_ci     * Therefore, instead of making the thread realtime, just give it the highest non-realtime priority. */
51353a5a1b3Sopenharmony_ci    if (SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL)) {
51453a5a1b3Sopenharmony_ci        pa_log_info("Successfully enabled THREAD_PRIORITY_TIME_CRITICAL scheduling for thread.");
51553a5a1b3Sopenharmony_ci        return 0;
51653a5a1b3Sopenharmony_ci    }
51753a5a1b3Sopenharmony_ci
51853a5a1b3Sopenharmony_ci    pa_log_warn("SetThreadPriority() failed: 0x%08lX", GetLastError());
51953a5a1b3Sopenharmony_ci    errno = EPERM;
52053a5a1b3Sopenharmony_ci#else
52153a5a1b3Sopenharmony_ci    errno = ENOTSUP;
52253a5a1b3Sopenharmony_ci#endif
52353a5a1b3Sopenharmony_ci    pa_log_info("Failed to acquire real-time scheduling: %s", pa_cstrerror(errno));
52453a5a1b3Sopenharmony_ci    return -1;
52553a5a1b3Sopenharmony_ci}
526