mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-19 06:46:38 +00:00
systemclock: Use futex_time64
syscall if available (32-bit systems) and use correct struct timespec
definition
See also https://gitlab.gnome.org/GNOME/glib/-/issues/2634 Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/1648 Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3561>
This commit is contained in:
parent
6687e7ed17
commit
9ca6b1196e
2 changed files with 120 additions and 14 deletions
|
@ -70,11 +70,15 @@
|
|||
#define GST_SYSTEM_CLOCK_WAIT(clock) g_cond_wait(GST_SYSTEM_CLOCK_GET_COND(clock),GST_SYSTEM_CLOCK_GET_LOCK(clock))
|
||||
#define GST_SYSTEM_CLOCK_BROADCAST(clock) g_cond_broadcast(GST_SYSTEM_CLOCK_GET_COND(clock))
|
||||
|
||||
#if defined(HAVE_FUTEX)
|
||||
#if defined(HAVE_FUTEX) || defined(HAVE_FUTEX_TIME64)
|
||||
#include <unistd.h>
|
||||
#include <linux/futex.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#if !defined(__NR_futex) && !defined(__NR_futex_time64)
|
||||
#error "Neither __NR_futex nor __NR_futex_time64 are defined but were found by meson"
|
||||
#endif
|
||||
|
||||
#ifndef FUTEX_WAIT_BITSET_PRIVATE
|
||||
#define FUTEX_WAIT_BITSET_PRIVATE FUTEX_WAIT_BITSET
|
||||
#endif
|
||||
|
@ -123,14 +127,35 @@ gst_futex_cond_broadcast (guint * cond_val)
|
|||
{
|
||||
g_atomic_int_inc (cond_val);
|
||||
|
||||
#if defined(__NR_futex_time64)
|
||||
{
|
||||
int res;
|
||||
res = syscall (__NR_futex_time64, cond_val, (gsize) FUTEX_WAKE_PRIVATE,
|
||||
(gsize) INT_MAX, NULL);
|
||||
|
||||
/* If the syscall does not exist (`ENOSYS`), we retry again below with the
|
||||
* normal `futex` syscall. This can happen if newer kernel headers are
|
||||
* used than the kernel that is actually running.
|
||||
*/
|
||||
#ifdef __NR_futex
|
||||
if (res >= 0 || errno != ENOSYS) {
|
||||
#else
|
||||
{
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__NR_futex)
|
||||
syscall (__NR_futex, cond_val, (gsize) FUTEX_WAKE_PRIVATE, (gsize) INT_MAX,
|
||||
NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_futex_cond_wait_until (guint * cond_val, GMutex * mutex, gint64 end_time)
|
||||
{
|
||||
struct timespec end;
|
||||
guint sampled;
|
||||
int res;
|
||||
gboolean success;
|
||||
|
@ -138,11 +163,78 @@ gst_futex_cond_wait_until (guint * cond_val, GMutex * mutex, gint64 end_time)
|
|||
if (end_time < 0)
|
||||
return FALSE;
|
||||
|
||||
sampled = *cond_val;
|
||||
g_mutex_unlock (mutex);
|
||||
|
||||
/* `struct timespec` as defined by the libc headers does not necessarily
|
||||
* have any relation to the one used by the kernel for the `futex` syscall.
|
||||
*
|
||||
* Specifically, the libc headers might use 64-bit `time_t` while the kernel
|
||||
* headers use 32-bit `__kernel_old_time_t` on certain systems.
|
||||
*
|
||||
* To get around this problem we
|
||||
* a) check if `futex_time64` is available, which only exists on 32-bit
|
||||
* platforms and always uses 64-bit `time_t`.
|
||||
* b) otherwise (or if that returns `ENOSYS`), we call the normal `futex`
|
||||
* syscall with the `struct timespec_t` used by the kernel, which uses
|
||||
* `__kernel_long_t` for both its fields. We use that instead of
|
||||
* `__kernel_old_time_t` because it is equivalent and available in the
|
||||
* kernel headers for a longer time.
|
||||
*
|
||||
* Also some 32-bit systems do not define `__NR_futex` at all and only
|
||||
* define `__NR_futex_time64`.
|
||||
*/
|
||||
|
||||
#ifdef __NR_futex_time64
|
||||
{
|
||||
struct
|
||||
{
|
||||
gint64 tv_sec;
|
||||
gint64 tv_nsec;
|
||||
} end;
|
||||
|
||||
end.tv_sec = end_time / 1000000000;
|
||||
end.tv_nsec = end_time % 1000000000;
|
||||
|
||||
/* we use FUTEX_WAIT_BITSET_PRIVATE rather than FUTEX_WAIT_PRIVATE to be
|
||||
* able to use absolute time */
|
||||
res =
|
||||
syscall (__NR_futex_time64, cond_val, (gsize) FUTEX_WAIT_BITSET_PRIVATE,
|
||||
(gsize) sampled, &end, NULL, FUTEX_BITSET_MATCH_ANY);
|
||||
|
||||
/* If the syscall does not exist (`ENOSYS`), we retry again below with the
|
||||
* normal `futex` syscall. This can happen if newer kernel headers are
|
||||
* used than the kernel that is actually running.
|
||||
*/
|
||||
#ifdef __NR_futex
|
||||
if (res >= 0 || errno != ENOSYS) {
|
||||
#else
|
||||
{
|
||||
#endif
|
||||
success = (res < 0 && errno == ETIMEDOUT) ? FALSE : TRUE;
|
||||
g_mutex_lock (mutex);
|
||||
|
||||
return success;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __NR_futex
|
||||
{
|
||||
struct
|
||||
{
|
||||
__kernel_long_t tv_sec;
|
||||
__kernel_long_t tv_nsec;
|
||||
} end;
|
||||
|
||||
/* Make sure to only ever call this if the end time actually fits into the
|
||||
* target type */
|
||||
g_assert (sizeof (__kernel_long_t) >= 8
|
||||
|| end_time / 1000000000 <= G_MAXINT32);
|
||||
|
||||
end.tv_sec = end_time / 1000000000;
|
||||
end.tv_nsec = end_time % 1000000000;
|
||||
|
||||
sampled = *cond_val;
|
||||
g_mutex_unlock (mutex);
|
||||
/* we use FUTEX_WAIT_BITSET_PRIVATE rather than FUTEX_WAIT_PRIVATE to be
|
||||
* able to use absolute time */
|
||||
res =
|
||||
|
@ -153,6 +245,11 @@ gst_futex_cond_wait_until (guint * cond_val, GMutex * mutex, gint64 end_time)
|
|||
|
||||
return success;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* We can't end up here because of the checks above */
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
#elif defined (G_OS_UNIX)
|
||||
#define GST_SYSTEM_CLOCK_ENTRY_GET_LOCK(entry) (&(entry)->lock)
|
||||
|
|
|
@ -294,7 +294,7 @@ if cc.has_header_symbol('pthread.h', 'pthread_cond_timedwait_relative_np')
|
|||
endif
|
||||
|
||||
# Check for futex(2)
|
||||
if cc.links('''#include <linux/futex.h>
|
||||
if cc.compiles('''#include <linux/futex.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
int main (int argc, char ** argv) {
|
||||
|
@ -303,6 +303,15 @@ if cc.links('''#include <linux/futex.h>
|
|||
}''', name : 'futex(2) system call')
|
||||
cdata.set('HAVE_FUTEX', 1)
|
||||
endif
|
||||
if cc.compiles('''#include <linux/futex.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
int main (int argc, char ** argv) {
|
||||
syscall (__NR_futex_time64, NULL, FUTEX_WAKE, FUTEX_WAIT);
|
||||
return 0;
|
||||
}''', name : 'futex(2) system call')
|
||||
cdata.set('HAVE_FUTEX_TIME64', 1)
|
||||
endif
|
||||
|
||||
# Check for posix timers and monotonic clock
|
||||
time_prefix = '#include <time.h>\n'
|
||||
|
|
Loading…
Reference in a new issue