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_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))
|
#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 <unistd.h>
|
||||||
#include <linux/futex.h>
|
#include <linux/futex.h>
|
||||||
#include <sys/syscall.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
|
#ifndef FUTEX_WAIT_BITSET_PRIVATE
|
||||||
#define FUTEX_WAIT_BITSET_PRIVATE FUTEX_WAIT_BITSET
|
#define FUTEX_WAIT_BITSET_PRIVATE FUTEX_WAIT_BITSET
|
||||||
#endif
|
#endif
|
||||||
|
@ -123,14 +127,35 @@ gst_futex_cond_broadcast (guint * cond_val)
|
||||||
{
|
{
|
||||||
g_atomic_int_inc (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,
|
syscall (__NR_futex, cond_val, (gsize) FUTEX_WAKE_PRIVATE, (gsize) INT_MAX,
|
||||||
NULL);
|
NULL);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_futex_cond_wait_until (guint * cond_val, GMutex * mutex, gint64 end_time)
|
gst_futex_cond_wait_until (guint * cond_val, GMutex * mutex, gint64 end_time)
|
||||||
{
|
{
|
||||||
struct timespec end;
|
|
||||||
guint sampled;
|
guint sampled;
|
||||||
int res;
|
int res;
|
||||||
gboolean success;
|
gboolean success;
|
||||||
|
@ -138,20 +163,92 @@ gst_futex_cond_wait_until (guint * cond_val, GMutex * mutex, gint64 end_time)
|
||||||
if (end_time < 0)
|
if (end_time < 0)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
end.tv_sec = end_time / 1000000000;
|
|
||||||
end.tv_nsec = end_time % 1000000000;
|
|
||||||
|
|
||||||
sampled = *cond_val;
|
sampled = *cond_val;
|
||||||
g_mutex_unlock (mutex);
|
g_mutex_unlock (mutex);
|
||||||
/* we use FUTEX_WAIT_BITSET_PRIVATE rather than FUTEX_WAIT_PRIVATE to be
|
|
||||||
* able to use absolute time */
|
|
||||||
res =
|
|
||||||
syscall (__NR_futex, cond_val, (gsize) FUTEX_WAIT_BITSET_PRIVATE,
|
|
||||||
(gsize) sampled, &end, NULL, FUTEX_BITSET_MATCH_ANY);
|
|
||||||
success = (res < 0 && errno == ETIMEDOUT) ? FALSE : TRUE;
|
|
||||||
g_mutex_lock (mutex);
|
|
||||||
|
|
||||||
return success;
|
/* `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;
|
||||||
|
|
||||||
|
/* we use FUTEX_WAIT_BITSET_PRIVATE rather than FUTEX_WAIT_PRIVATE to be
|
||||||
|
* able to use absolute time */
|
||||||
|
res =
|
||||||
|
syscall (__NR_futex, cond_val, (gsize) FUTEX_WAIT_BITSET_PRIVATE,
|
||||||
|
(gsize) sampled, &end, NULL, FUTEX_BITSET_MATCH_ANY);
|
||||||
|
success = (res < 0 && errno == ETIMEDOUT) ? FALSE : TRUE;
|
||||||
|
g_mutex_lock (mutex);
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* We can't end up here because of the checks above */
|
||||||
|
g_assert_not_reached ();
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined (G_OS_UNIX)
|
#elif defined (G_OS_UNIX)
|
||||||
|
|
|
@ -294,7 +294,7 @@ if cc.has_header_symbol('pthread.h', 'pthread_cond_timedwait_relative_np')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Check for futex(2)
|
# Check for futex(2)
|
||||||
if cc.links('''#include <linux/futex.h>
|
if cc.compiles('''#include <linux/futex.h>
|
||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
int main (int argc, char ** argv) {
|
int main (int argc, char ** argv) {
|
||||||
|
@ -303,6 +303,15 @@ if cc.links('''#include <linux/futex.h>
|
||||||
}''', name : 'futex(2) system call')
|
}''', name : 'futex(2) system call')
|
||||||
cdata.set('HAVE_FUTEX', 1)
|
cdata.set('HAVE_FUTEX', 1)
|
||||||
endif
|
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
|
# Check for posix timers and monotonic clock
|
||||||
time_prefix = '#include <time.h>\n'
|
time_prefix = '#include <time.h>\n'
|
||||||
|
|
Loading…
Reference in a new issue