Commit 16f049a0 authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

linux: add wait-on-address/futex functions

This only provides the Linux back-end. Those functions are not exported
since they are not universally available (and not meant to be used by
plugins at this point).
parent 113ded6a
......@@ -3,7 +3,7 @@
* This header provides portable declarations for mutexes & conditions
*****************************************************************************
* Copyright (C) 1999, 2002 VLC authors and VideoLAN
* Copyright © 2007-2008 Rémi Denis-Courmont
* Copyright © 2007-2016 Rémi Denis-Courmont
*
* Authors: Jean-Marc Dressler <polux@via.ecp.fr>
* Samuel Hocevar <sam@via.ecp.fr>
......@@ -599,6 +599,57 @@ VLC_API int vlc_threadvar_set(vlc_threadvar_t key, void *value);
*/
VLC_API void *vlc_threadvar_get(vlc_threadvar_t);
/**
* Waits on an address.
*
* Puts the calling thread to sleep if a specific value is stored at a
* specified address. If the value does not match, do nothing and return
* immediately.
*
* \param addr address to check for
* \param val value to match at the address
*/
void vlc_addr_wait(void *addr, int val);
/**
* Waits on an address with a time-out.
*
* This function operates as vlc_addr_wait() but provides an additional
* time-out. If the time-out elapses, the thread resumes and the function
* returns.
*
* \param addr address to check for
* \param val value to match at the address
* \param delay time-out duration
*
* \return true if the function was woken up before the time-out,
* false if the time-out elapsed.
*/
bool vlc_addr_timedwait(void *addr, int val, mtime_t delay);
/**
* Wakes up one thread on an address.
*
* Wakes up (at least) one of the thread sleeping on the specified address.
* The address must be equal to the first parameter given by at least one
* thread sleeping within the vlc_addr_wait() or vlc_addr_timedwait()
* functions. If no threads are found, this function does nothing.
*
* \param addr address identifying which threads may be woken up
*/
void vlc_addr_signal(void *addr);
/**
* Wakes up all thread on an address.
*
* Wakes up all threads sleeping on the specified address (if any).
* Any thread sleeping within a call to vlc_addr_wait() or vlc_addr_timedwait()
* with the specified address as first call parameter will be woken up.
*
* \param addr address identifying which threads to wake up
*/
void vlc_addr_broadcast(void *addr);
/**
* Creates and starts a new thread.
*
......
......@@ -22,11 +22,20 @@
# include "config.h"
#endif
#include <vlc_common.h>
#include <errno.h>
#include <limits.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <linux/futex.h>
#ifndef FUTEX_PRIVATE_FLAG
#define FUTEX_WAKE_PRIVATE FUTEX_WAKE
#define FUTEX_WAIT_PRIVATE FUTEX_WAIT
#endif
#include <vlc_common.h>
unsigned long vlc_thread_id(void)
{
......@@ -37,3 +46,42 @@ unsigned long vlc_thread_id(void)
return tid;
}
static int sys_futex(void *addr, int op, int val, const struct timespec *to,
void *addr2, int val3)
{
return syscall(SYS_futex, addr, op, val, to, addr2, val3);
}
static int vlc_futex_wake(void *addr, int nr)
{
return sys_futex(addr, FUTEX_WAKE_PRIVATE, nr, NULL, NULL, 0);
}
static int vlc_futex_wait(void *addr, int val, const struct timespec *to)
{
return sys_futex(addr, FUTEX_WAIT_PRIVATE, val, to, NULL, 0);
}
void vlc_addr_signal(void *addr)
{
vlc_futex_wake(addr, 1);
}
void vlc_addr_broadcast(void *addr)
{
vlc_futex_wake(addr, INT_MAX);
}
void vlc_addr_wait(void *addr, int val)
{
vlc_futex_wait(addr, val, NULL);
}
bool vlc_addr_timedwait(void *addr, int val, mtime_t delay)
{
lldiv_t d = lldiv(delay, CLOCK_FREQ);
struct timespec ts = { d.quot, d.rem * (1000000000 / CLOCK_FREQ) };
return (vlc_futex_wait(addr, val, &ts) == 0 || errno != ETIMEDOUT);
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment