1 /*****************************************************************************
2 * linux/thread.c: Linux specifics for threading
3 *****************************************************************************
4 * Copyright (C) 2016 Rémi Denis-Courmont
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 *****************************************************************************/
20
21 #ifdef HAVE_CONFIG_H
22 # include "config.h"
23 #endif
24
25 #include <errno.h>
26 #include <limits.h>
27 #include <stdlib.h>
28 #include <sys/types.h>
29 #include <unistd.h>
30 #include <sys/syscall.h>
31 #include <linux/futex.h>
32
33 #ifndef FUTEX_PRIVATE_FLAG
34 #define FUTEX_WAKE_PRIVATE FUTEX_WAKE
35 #define FUTEX_WAIT_PRIVATE FUTEX_WAIT
36 #endif
37
38 #include <vlc_common.h>
39
vlc_thread_id(void)40 unsigned long vlc_thread_id(void)
41 {
42 static __thread pid_t tid = 0;
43
44 if (unlikely(tid == 0))
45 tid = syscall(__NR_gettid);
46
47 return tid;
48 }
49
sys_futex(void * addr,int op,unsigned val,const struct timespec * to,void * addr2,int val3)50 static int sys_futex(void *addr, int op, unsigned val,
51 const struct timespec *to, void *addr2, int val3)
52 {
53 return syscall(__NR_futex, addr, op, val, to, addr2, val3);
54 }
55
vlc_futex_wake(void * addr,int nr)56 static int vlc_futex_wake(void *addr, int nr)
57 {
58 return sys_futex(addr, FUTEX_WAKE_PRIVATE, nr, NULL, NULL, 0);
59 }
60
vlc_futex_wait(void * addr,unsigned val,const struct timespec * to)61 static int vlc_futex_wait(void *addr, unsigned val, const struct timespec *to)
62 {
63 return sys_futex(addr, FUTEX_WAIT_PRIVATE, val, to, NULL, 0);
64 }
65
vlc_addr_signal(void * addr)66 void vlc_addr_signal(void *addr)
67 {
68 vlc_futex_wake(addr, 1);
69 }
70
vlc_addr_broadcast(void * addr)71 void vlc_addr_broadcast(void *addr)
72 {
73 vlc_futex_wake(addr, INT_MAX);
74 }
75
vlc_addr_wait(void * addr,unsigned val)76 void vlc_addr_wait(void *addr, unsigned val)
77 {
78 vlc_futex_wait(addr, val, NULL);
79 }
80
vlc_addr_timedwait(void * addr,unsigned val,mtime_t delay)81 bool vlc_addr_timedwait(void *addr, unsigned val, mtime_t delay)
82 {
83 lldiv_t d = lldiv(delay, CLOCK_FREQ);
84 struct timespec ts = { d.quot, d.rem * (1000000000 / CLOCK_FREQ) };
85
86 return (vlc_futex_wait(addr, val, &ts) == 0 || errno != ETIMEDOUT);
87 }
88