2016-08-30 16:30:37 +03:00
/*
2016-10-30 23:44:50 +03:00
* Copyright ( c ) 2016 Eugene Syromyatnikov < evgsyr @ gmail . com >
2016-08-30 16:30:37 +03:00
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
* 1. Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
* 2. Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission .
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ` ` AS IS ' ' AND ANY EXPRESS OR
* IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED .
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT , INDIRECT ,
* INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT
* NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
* DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
# include "tests.h"
# include <asm/unistd.h>
# ifdef __NR_futex
# include <errno.h>
# include <stdarg.h>
# include <stdbool.h>
# include <stdio.h>
# include <stdint.h>
# include <unistd.h>
# include <sys / time.h>
# ifndef FUTEX_PRIVATE_FLAG
# define FUTEX_PRIVATE_FLAG 128
# endif
# ifndef FUTEX_CLOCK_REALTIME
# define FUTEX_CLOCK_REALTIME 256
# endif
# ifndef FUTEX_CMD_MASK
# define FUTEX_CMD_MASK ~(FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME)
# endif
# include "xlat.h"
# include "xlat / futexops.h"
# include "xlat / futexwakeops.h"
# include "xlat / futexwakecmps.h"
static struct timespec * tmout ;
void futex_error ( int * uaddr , int op , unsigned long val , unsigned long timeout ,
int * uaddr2 , unsigned long val3 , int rc )
{
perror_msg_and_fail ( " futex(%p, %#x, %#x, %#lx, %p, %#x) = %d " ,
2016-09-15 23:04:07 +03:00
uaddr , op , ( unsigned ) val , timeout , uaddr , ( unsigned ) val3 , rc ) ;
2016-08-30 16:30:37 +03:00
}
# define CHECK_FUTEX_GENERIC(uaddr, op, val, timeout, uaddr2, val3, check, \
enosys ) \
do { \
rc = syscall ( __NR_futex , ( uaddr ) , ( op ) , ( val ) , ( timeout ) , \
( uaddr2 ) , ( val3 ) ) ; \
/* It is here due to EPERM on WAKE_OP on AArch64 */ \
if ( ( rc = = - 1 ) & & ( errno = = EPERM ) ) \
break ; \
if ( enosys & & ( rc = = - 1 ) & & ( errno = = ENOSYS ) ) \
break ; \
if ( ! ( check ) ) \
futex_error ( ( uaddr ) , ( op ) , ( val ) , \
2016-09-15 23:04:07 +03:00
( unsigned long ) ( timeout ) , ( int * ) ( uaddr2 ) , \
2016-08-30 16:30:37 +03:00
( val3 ) , rc ) ; \
} while ( 0 )
# define CHECK_FUTEX_ENOSYS(uaddr, op, val, timeout, uaddr2, val3, check) \
CHECK_FUTEX_GENERIC ( uaddr , op , val , timeout , uaddr2 , val3 , check , 1 )
# define CHECK_FUTEX(uaddr, op, val, timeout, uaddr2, val3, check) \
CHECK_FUTEX_GENERIC ( uaddr , op , val , timeout , uaddr2 , val3 , check , 0 )
enum argmask {
ARG3 = 1 < < 0 ,
ARG4 = 1 < < 1 ,
ARG5 = 1 < < 2 ,
ARG6 = 1 < < 3 ,
} ;
void invalid_op ( int * val , int op , uint32_t argmask , . . . )
{
static const unsigned long args [ ] = {
2016-09-15 23:04:07 +03:00
( unsigned long ) 0xface1e55deadbee1ULL ,
( unsigned long ) 0xface1e56deadbee2ULL ,
( unsigned long ) 0xface1e57deadbee3ULL ,
( unsigned long ) 0xface1e58deadbee4ULL ,
2016-08-30 16:30:37 +03:00
} ;
/* Since timeout value is copied before full op check, we should provide
* some valid timeout address or NULL */
int cmd = op & FUTEX_CMD_MASK ;
bool valid_timeout = ( cmd = = FUTEX_WAIT ) | | ( cmd = = FUTEX_LOCK_PI ) | |
( cmd = = FUTEX_WAIT_BITSET ) | | ( cmd = = FUTEX_WAIT_REQUEUE_PI ) ;
bool timeout_is_val2 = ( cmd = = FUTEX_REQUEUE ) | |
( cmd = = FUTEX_CMP_REQUEUE ) | | ( cmd = = FUTEX_WAKE_OP ) | |
( cmd = = FUTEX_CMP_REQUEUE_PI ) ;
const char * fmt ;
int saved_errno ;
int rc ;
int i ;
va_list ap ;
CHECK_FUTEX ( val , op , args [ 0 ] , valid_timeout ? 0 : args [ 1 ] , args [ 2 ] ,
args [ 3 ] , ( rc = = - 1 ) & & ( errno = = ENOSYS ) ) ;
saved_errno = errno ;
printf ( " futex(%p, %#x /* FUTEX_??? */ " , val , op ) ;
va_start ( ap , argmask ) ;
for ( i = 0 ; i < 4 ; i + + ) {
if ( argmask & ( 1 < < i ) ) {
fmt = va_arg ( ap , const char * ) ;
printf ( " , " ) ;
if ( ( ( 1 < < i ) = = ARG3 ) | | ( ( 1 < < i ) = = ARG6 ) | |
( ( ( 1 < < i ) = = ARG4 ) & & timeout_is_val2 ) )
2016-09-15 23:04:07 +03:00
printf ( fmt , ( unsigned ) args [ i ] ) ;
2016-08-30 16:30:37 +03:00
else
printf ( fmt , args [ i ] ) ;
}
}
va_end ( ap ) ;
errno = saved_errno ;
printf ( " ) = -1 ENOSYS (%m) \n " ) ;
}
# define CHECK_INVALID_CLOCKRT(op, ...) \
do { \
invalid_op ( uaddr , FUTEX_CLOCK_REALTIME | ( op ) , __VA_ARGS__ ) ; \
invalid_op ( uaddr , FUTEX_CLOCK_REALTIME | FUTEX_PRIVATE_FLAG | \
( op ) , __VA_ARGS__ ) ; \
} while ( 0 )
/* Value which differs from one stored in int *val */
2016-09-15 23:04:07 +03:00
# define VAL ((unsigned long) 0xbadda7a0facefeedLLU)
# define VAL_PR ((unsigned) VAL)
2016-08-30 16:30:37 +03:00
2016-09-15 23:04:07 +03:00
# define VAL2 ((unsigned long) 0xbadda7a0ca7b100dLLU)
# define VAL2_PR ((unsigned) VAL2)
2016-08-30 16:30:37 +03:00
2016-09-15 23:04:07 +03:00
# define VAL3 ((unsigned long) 0xbadda7a09caffee1LLU)
# define VAL3_PR ((unsigned) VAL3)
2016-08-30 16:30:37 +03:00
int
main ( int argc , char * argv [ ] )
{
int * uaddr = tail_alloc ( sizeof ( * uaddr ) ) ;
int * uaddr2 = tail_alloc ( sizeof ( * uaddr2 ) ) ;
int rc ;
unsigned i ;
unsigned j ;
uaddr [ 0 ] = 0x1deadead ;
uaddr2 [ 0 ] = 0xbadf00d ;
tmout = tail_alloc ( sizeof ( * tmout ) ) ;
tmout - > tv_sec = 123 ;
tmout - > tv_nsec = 0xbadc0de ;
/* FUTEX_WAIT - check whether uaddr == val and sleep
* Possible flags : PRIVATE , CLOCK_RT ( since 4.5 )
* 1. uaddr - futex address
* 2. op - FUTEX_WAIT
* 3. val - expected value
* 4. timeout - address to timespec with timeout
* 5. uaddr2 - not used
* 6. val3 - not used
*/
/* uaddr is NULL */
CHECK_FUTEX ( NULL , FUTEX_WAIT , VAL , tmout , uaddr2 , VAL3 ,
( rc = = - 1 ) & & ( errno = = EFAULT ) ) ;
2016-11-25 00:48:00 +03:00
printf ( " futex(NULL, FUTEX_WAIT, %u, {tv_sec=%jd, tv_nsec=%jd}) = %s \n " ,
2016-09-15 23:04:07 +03:00
VAL_PR , ( intmax_t ) tmout - > tv_sec , ( intmax_t ) tmout - > tv_nsec ,
2016-09-02 18:25:35 +03:00
sprintrc ( rc ) ) ;
2016-08-30 16:30:37 +03:00
/* uaddr is faulty */
CHECK_FUTEX ( uaddr + 1 , FUTEX_WAIT , VAL , tmout , uaddr2 , VAL3 ,
( rc = = - 1 ) & & ( errno = = EFAULT ) ) ;
2016-11-25 00:48:00 +03:00
printf ( " futex(%p, FUTEX_WAIT, %u, {tv_sec=%jd, tv_nsec=%jd}) = %s \n " ,
2016-09-15 23:04:07 +03:00
uaddr + 1 , VAL_PR , ( intmax_t ) tmout - > tv_sec ,
( intmax_t ) tmout - > tv_nsec , sprintrc ( rc ) ) ;
2016-08-30 16:30:37 +03:00
/* timeout is faulty */
CHECK_FUTEX ( uaddr , FUTEX_WAIT , VAL , tmout + 1 , uaddr2 , VAL3 ,
( rc = = - 1 ) & & ( errno = = EFAULT ) ) ;
printf ( " futex(%p, FUTEX_WAIT, %u, %p) = %s \n " ,
2016-09-02 18:25:35 +03:00
uaddr , 0xfacefeed , tmout + 1 , sprintrc ( rc ) ) ;
2016-08-30 16:30:37 +03:00
/* uaddr is not as provided; uaddr2 is faulty but ignored */
CHECK_FUTEX ( uaddr , FUTEX_WAIT , VAL , tmout , uaddr2 + 1 , VAL3 ,
( rc = = - 1 ) & & ( errno = = EAGAIN ) ) ;
2016-11-25 00:48:00 +03:00
printf ( " futex(%p, FUTEX_WAIT, %u, {tv_sec=%jd, tv_nsec=%jd}) = %s \n " ,
2016-09-15 23:04:07 +03:00
uaddr , VAL_PR , ( intmax_t ) tmout - > tv_sec ,
( intmax_t ) tmout - > tv_nsec , sprintrc ( rc ) ) ;
2016-08-30 16:30:37 +03:00
/* uaddr is not as provided; uaddr2 is faulty but ignored */
CHECK_FUTEX_ENOSYS ( uaddr , FUTEX_PRIVATE_FLAG | FUTEX_WAIT , VAL , tmout ,
uaddr2 + 1 , VAL3 , ( rc = = - 1 ) & & ( errno = = EAGAIN ) ) ;
2016-11-25 00:48:00 +03:00
printf ( " futex(%p, FUTEX_WAIT_PRIVATE, %u, {tv_sec=%jd, tv_nsec=%jd}) = "
" %s \n " ,
2016-09-15 23:04:07 +03:00
uaddr , VAL_PR , ( intmax_t ) tmout - > tv_sec ,
( intmax_t ) tmout - > tv_nsec , sprintrc ( rc ) ) ;
2016-08-30 16:30:37 +03:00
/* Next 2 tests are with CLOCKRT bit set */
/* Valid after v4.4-rc2-27-g337f130 */
CHECK_FUTEX_ENOSYS ( uaddr ,
FUTEX_CLOCK_REALTIME | FUTEX_WAIT ,
VAL , tmout , uaddr2 , VAL3 , ( rc = = - 1 ) & & ( errno = = EAGAIN ) ) ;
printf ( " futex(%p, FUTEX_WAIT|FUTEX_CLOCK_REALTIME, %u, "
2016-11-25 00:48:00 +03:00
" {tv_sec=%jd, tv_nsec=%jd}) = %s \n " , uaddr , VAL_PR ,
2016-09-15 23:04:07 +03:00
( intmax_t ) tmout - > tv_sec , ( intmax_t ) tmout - > tv_nsec ,
2016-09-02 18:25:35 +03:00
sprintrc ( rc ) ) ;
2016-08-30 16:30:37 +03:00
CHECK_FUTEX_ENOSYS ( uaddr ,
FUTEX_CLOCK_REALTIME | FUTEX_PRIVATE_FLAG | FUTEX_WAIT ,
VAL , tmout , uaddr2 , 0 , ( rc = = - 1 ) & & ( errno = = EAGAIN ) ) ;
printf ( " futex(%p, FUTEX_WAIT_PRIVATE|FUTEX_CLOCK_REALTIME, %u, "
2016-11-25 00:48:00 +03:00
" {tv_sec=%jd, tv_nsec=%jd}) = %s \n " , uaddr , VAL_PR ,
2016-09-15 23:04:07 +03:00
( intmax_t ) tmout - > tv_sec , ( intmax_t ) tmout - > tv_nsec ,
2016-09-02 18:25:35 +03:00
sprintrc ( rc ) ) ;
2016-08-30 16:30:37 +03:00
/* FUTEX_WAIT_BITSET - FUTEX_WAIT which provides additional bitmask
* which should be matched at least in one bit with
* wake mask in order to wake .
* Possible flags : PRIVATE , CLOCKRT
* 1. uaddr - futex address
* 2. op - FUTEX_TRYLOCK_PI
* 3. val - expected value stored in uaddr
* 4. timeout - timeout
* 5. uaddr2 - not used
* 6. val3 - bitmask
*/
CHECK_FUTEX_ENOSYS ( uaddr , FUTEX_WAIT_BITSET , VAL , tmout , uaddr2 + 1 ,
VAL3 , ( rc = = - 1 ) & & ( errno = = EAGAIN ) ) ;
2016-11-25 00:48:00 +03:00
printf ( " futex(%p, FUTEX_WAIT_BITSET, %u, {tv_sec=%jd, tv_nsec=%jd}, "
" %#x) = %s \n " ,
2016-09-15 23:04:07 +03:00
uaddr , VAL_PR , ( intmax_t ) tmout - > tv_sec ,
( intmax_t ) tmout - > tv_nsec , VAL3_PR , sprintrc ( rc ) ) ;
2016-08-30 16:30:37 +03:00
/* val3 of 0 is invalid */
CHECK_FUTEX_ENOSYS ( uaddr , FUTEX_WAIT_BITSET , VAL , tmout , uaddr2 + 1 , 0 ,
( rc = = - 1 ) & & ( errno = = EINVAL ) ) ;
2016-11-25 00:48:00 +03:00
printf ( " futex(%p, FUTEX_WAIT_BITSET, %u, {tv_sec=%jd, tv_nsec=%jd}, "
" %#x) = %s \n " ,
2016-09-15 23:04:07 +03:00
uaddr , VAL_PR , ( intmax_t ) tmout - > tv_sec ,
( intmax_t ) tmout - > tv_nsec , 0 , sprintrc ( rc ) ) ;
2016-08-30 16:30:37 +03:00
CHECK_FUTEX_ENOSYS ( uaddr , FUTEX_PRIVATE_FLAG | FUTEX_WAIT_BITSET , VAL ,
tmout , uaddr2 + 1 , VAL3 , ( rc = = - 1 ) & & ( errno = = EAGAIN ) ) ;
2016-11-25 00:48:00 +03:00
printf ( " futex(%p, FUTEX_WAIT_BITSET_PRIVATE, %u, "
" {tv_sec=%jd, tv_nsec=%jd}, %#x) = %s \n " ,
uaddr , VAL_PR , ( intmax_t ) tmout - > tv_sec ,
2016-09-15 23:04:07 +03:00
( intmax_t ) tmout - > tv_nsec , VAL3_PR , sprintrc ( rc ) ) ;
2016-08-30 16:30:37 +03:00
/* Next 3 tests are with CLOCKRT bit set */
CHECK_FUTEX_ENOSYS ( uaddr , FUTEX_CLOCK_REALTIME | FUTEX_WAIT_BITSET , VAL ,
tmout , uaddr2 + 1 , VAL3 , ( rc = = - 1 ) & & ( errno = = EAGAIN ) ) ;
printf ( " futex(%p, FUTEX_WAIT_BITSET|FUTEX_CLOCK_REALTIME, %u, "
2016-11-25 00:48:00 +03:00
" {tv_sec=%jd, tv_nsec=%jd}, %#x) = %s \n " , uaddr , VAL_PR ,
2016-09-15 23:04:07 +03:00
( intmax_t ) tmout - > tv_sec , ( intmax_t ) tmout - > tv_nsec , VAL3_PR ,
2016-09-02 18:25:35 +03:00
sprintrc ( rc ) ) ;
2016-08-30 16:30:37 +03:00
/* val3 of 0 is invalid */
CHECK_FUTEX_ENOSYS ( uaddr , FUTEX_CLOCK_REALTIME | FUTEX_WAIT_BITSET , VAL ,
tmout , uaddr2 + 1 , 0 , ( rc = = - 1 ) & & ( errno = = EINVAL ) ) ;
printf ( " futex(%p, FUTEX_WAIT_BITSET|FUTEX_CLOCK_REALTIME, %u, "
2016-11-25 00:48:00 +03:00
" {tv_sec=%jd, tv_nsec=%jd}, %#x) = %s \n " , uaddr , VAL_PR ,
2016-09-15 23:04:07 +03:00
( intmax_t ) tmout - > tv_sec , ( intmax_t ) tmout - > tv_nsec , 0 ,
2016-09-02 18:25:35 +03:00
sprintrc ( rc ) ) ;
2016-08-30 16:30:37 +03:00
CHECK_FUTEX_ENOSYS ( uaddr , FUTEX_CLOCK_REALTIME | FUTEX_PRIVATE_FLAG |
FUTEX_WAIT_BITSET , VAL , tmout , uaddr2 + 1 , VAL3 ,
( rc = = - 1 ) & & ( errno = = EAGAIN ) ) ;
printf ( " futex(%p, FUTEX_WAIT_BITSET_PRIVATE|FUTEX_CLOCK_REALTIME, %u, "
2016-11-25 00:48:00 +03:00
" {tv_sec=%jd, tv_nsec=%jd}, %#x) = %s \n " , uaddr , VAL_PR ,
2016-09-15 23:04:07 +03:00
( intmax_t ) tmout - > tv_sec , ( intmax_t ) tmout - > tv_nsec , VAL3_PR ,
2016-09-02 18:25:35 +03:00
sprintrc ( rc ) ) ;
2016-08-30 16:30:37 +03:00
/* FUTEX_WAKE - wake val processes waiting for uaddr
* Possible flags : PRIVATE
* 1. uaddr - futex address
* 2. op - FUTEX_WAKE
* 3. val - how many processes to wake
* 4. timeout - not used
* 5. uaddr2 - not used
* 6. val3 - not used
*/
/* Zero processes to wake is not a good idea, but it should return 0 */
CHECK_FUTEX ( uaddr , FUTEX_WAKE , 0 , NULL , NULL , 0 , ( rc = = 0 ) ) ;
2016-09-02 18:25:35 +03:00
printf ( " futex(%p, FUTEX_WAKE, %u) = %s \n " , uaddr , 0 , sprintrc ( rc ) ) ;
2016-08-30 16:30:37 +03:00
/* Trying to wake some processes, but there's nothing to wake */
CHECK_FUTEX ( uaddr , FUTEX_WAKE , 10 , NULL , NULL , 0 , ( rc = = 0 ) ) ;
2016-09-02 18:25:35 +03:00
printf ( " futex(%p, FUTEX_WAKE, %u) = %s \n " , uaddr , 10 , sprintrc ( rc ) ) ;
2016-08-30 16:30:37 +03:00
/* Trying to wake some processes, but there's nothing to wake */
CHECK_FUTEX_ENOSYS ( uaddr , FUTEX_PRIVATE_FLAG | FUTEX_WAKE , 10 , NULL ,
NULL , 0 , ( rc = = 0 ) ) ;
printf ( " futex(%p, FUTEX_WAKE_PRIVATE, %u) = %s \n " , uaddr , 10 ,
2016-09-02 18:25:35 +03:00
sprintrc ( rc ) ) ;
2016-08-30 16:30:37 +03:00
CHECK_INVALID_CLOCKRT ( FUTEX_WAKE , ARG3 , " %u " ) ;
/* FUTEX_WAKE_BITSET - wake val processes waiting for uaddr which has at
* least one common bit with bitset provided in
* val3 .
* Possible flags : PRIVATE
* 1. uaddr - futex address
* 2. op - FUTEX_WAKE
* 3. val - how many processes to wake
* 4. timeout - not used
* 5. uaddr2 - not used
* 6. val3 - bitmask
*/
/* Trying to wake some processes, but there's nothing to wake */
CHECK_FUTEX_ENOSYS ( uaddr , FUTEX_WAKE_BITSET , 10 , NULL , NULL ,
VAL3 , ( rc = = 0 ) ) ;
printf ( " futex(%p, FUTEX_WAKE_BITSET, %u, %#x) = %s \n " , uaddr , 10 ,
2016-09-02 18:25:35 +03:00
VAL3_PR , sprintrc ( rc ) ) ;
2016-08-30 16:30:37 +03:00
/* bitset 0 is invalid */
CHECK_FUTEX_ENOSYS ( uaddr , FUTEX_WAKE_BITSET , 10 , NULL , NULL , 0 ,
( rc = = - 1 ) & & ( errno = = EINVAL ) ) ;
printf ( " futex(%p, FUTEX_WAKE_BITSET, %u, %#x) = %s \n " , uaddr , 10 , 0 ,
2016-09-02 18:25:35 +03:00
sprintrc ( rc ) ) ;
2016-08-30 16:30:37 +03:00
/* Trying to wake some processes, but there's nothing to wake */
CHECK_FUTEX_ENOSYS ( uaddr , FUTEX_PRIVATE_FLAG | FUTEX_WAKE_BITSET , 10 ,
NULL , NULL , VAL3 , ( rc = = 0 ) ) ;
printf ( " futex(%p, FUTEX_WAKE_BITSET_PRIVATE, %u, %#x) = %s \n " , uaddr ,
2016-09-02 18:25:35 +03:00
10 , VAL3_PR , sprintrc ( rc ) ) ;
2016-08-30 16:30:37 +03:00
CHECK_INVALID_CLOCKRT ( FUTEX_WAKE_BITSET , ARG3 | ARG6 , " %u " , " %#x " ) ;
/* FUTEX_FD - deprecated
* Possible flags : PRIVATE
* 1. uaddr - futex address
* 2. op - FUTEX_FD
* 3. val - signal number
* 4. timeout - not used
* 5. uaddr2 - not used
* 6. val3 - not used
*/
/* FUTEX_FD is not implemented since 2.6.26 */
CHECK_FUTEX_ENOSYS ( uaddr , FUTEX_FD , VAL , NULL , NULL , VAL3 ,
( rc = = - 1 ) & & ( errno = = EINVAL ) ) ;
2016-09-02 18:25:35 +03:00
printf ( " futex(%p, FUTEX_FD, %u) = %s \n " , uaddr , VAL_PR , sprintrc ( rc ) ) ;
2016-08-30 16:30:37 +03:00
/* FUTEX_FD is not implemented since 2.6.26 */
CHECK_FUTEX_ENOSYS ( uaddr , FUTEX_PRIVATE_FLAG | FUTEX_FD , VAL , NULL ,
NULL , VAL3 , ( rc = = - 1 ) & & ( errno = = EINVAL ) ) ;
printf ( " futex(%p, FUTEX_FD|FUTEX_PRIVATE_FLAG, %u) = %s \n " , uaddr ,
2016-09-02 18:25:35 +03:00
VAL_PR , sprintrc ( rc ) ) ;
2016-08-30 16:30:37 +03:00
CHECK_INVALID_CLOCKRT ( FUTEX_FD , ARG3 , " %u " ) ;
/* FUTEX_REQUEUE - wake val processes and re-queue rest on uaddr2
* Possible flags : PRIVATE
* 1. uaddr - futex address
* 2. op - FUTEX_REQUEUE
* 3. val - how many processes to wake
* 4. val2 - amount of processes to re - queue on uadr2
* 5. uaddr2 - another futex address , to re - queue waiting processes on
* 6. val3 - not used
*/
/* Trying to re-queue some processes but there's nothing to re-queue */
CHECK_FUTEX ( uaddr , FUTEX_REQUEUE , VAL , VAL2 , uaddr2 , VAL3 ,
( rc = = 0 ) ) ;
printf ( " futex(%p, FUTEX_REQUEUE, %u, %u, %p) = %s \n " ,
2016-09-02 18:25:35 +03:00
uaddr , VAL_PR , VAL2_PR , uaddr2 , sprintrc ( rc ) ) ;
2016-08-30 16:30:37 +03:00
/* Trying to re-queue some processes but there's nothing to re-queue */
CHECK_FUTEX_ENOSYS ( uaddr , FUTEX_PRIVATE_FLAG | FUTEX_REQUEUE , VAL , VAL2 ,
uaddr2 , VAL3 , ( rc = = 0 ) ) ;
printf ( " futex(%p, FUTEX_REQUEUE_PRIVATE, %u, %u, %p) = %s \n " ,
2016-09-02 18:25:35 +03:00
uaddr , VAL_PR , VAL2_PR , uaddr2 , sprintrc ( rc ) ) ;
2016-08-30 16:30:37 +03:00
CHECK_INVALID_CLOCKRT ( FUTEX_REQUEUE , ARG3 | ARG4 | ARG5 , " %u " , " %u " ,
" %#lx " ) ;
/* FUTEX_CMP_REQUEUE - wake val processes and re-queue rest on uaddr2
* if uaddr has value val3
* Possible flags : PRIVATE
* 1. uaddr - futex address
* 2. op - FUTEX_CMP_REQUEUE
* 3. val - how many processes to wake
* 4. val2 - amount of processes to re - queue on uadr2
* 5. uaddr2 - another futex address , to re - queue waiting processes on
* 6. val3 - expected value stored in uaddr
*/
/* Comparison re-queue with wrong val value */
CHECK_FUTEX ( uaddr , FUTEX_CMP_REQUEUE , VAL , VAL2 , uaddr2 , VAL3 ,
( rc = = - 1 ) & & ( errno = = EAGAIN ) ) ;
printf ( " futex(%p, FUTEX_CMP_REQUEUE, %u, %u, %p, %u) = %s \n " ,
2016-09-02 18:25:35 +03:00
uaddr , VAL_PR , VAL2_PR , uaddr2 , VAL3_PR , sprintrc ( rc ) ) ;
2016-08-30 16:30:37 +03:00
/* Successful comparison re-queue */
CHECK_FUTEX ( uaddr , FUTEX_CMP_REQUEUE , VAL , VAL2 , uaddr2 , * uaddr ,
( rc = = 0 ) ) ;
printf ( " futex(%p, FUTEX_CMP_REQUEUE, %u, %u, %p, %u) = %s \n " ,
2016-09-02 18:25:35 +03:00
uaddr , VAL_PR , VAL2_PR , uaddr2 , * uaddr , sprintrc ( rc ) ) ;
2016-08-30 16:30:37 +03:00
/* Successful comparison re-queue */
CHECK_FUTEX_ENOSYS ( uaddr , FUTEX_PRIVATE_FLAG | FUTEX_CMP_REQUEUE , VAL ,
VAL2 , uaddr2 , * uaddr , ( rc = = 0 ) ) ;
printf ( " futex(%p, FUTEX_CMP_REQUEUE_PRIVATE, %u, %u, %p, %u) = %s \n " ,
2016-09-02 18:25:35 +03:00
uaddr , VAL_PR , VAL2_PR , uaddr2 , * uaddr , sprintrc ( rc ) ) ;
2016-08-30 16:30:37 +03:00
CHECK_INVALID_CLOCKRT ( FUTEX_CMP_REQUEUE , ARG3 | ARG4 | ARG5 | ARG6 ,
" %u " , " %u " , " %#lx " , " %u " ) ;
/* FUTEX_WAKE_OP - wake val processes waiting for uaddr, additionally
* wake val2 processes waiting for uaddr2 in case
* operation encoded in val3 ( change of value at uaddr2
* and comparison of previous value against provided
* constant ) succeedes with value at uaddr2 . Operation
* result is written to value of uaddr2 ( in any case ) .
* 1. uaddr - futex address
* 2. op - FUTEX_WAKE_OP
* 3. val - how many processes to wake
* 4. val2 - amount of processes to wake in case operation encoded in
* val3 returns true
* 5. uaddr2 - another futex address , for conditional wake of
* additional processes
* 6. val3 - encoded operation :
* 1. bit 31 - if 1 then value stored in field field 4
* should be interpreted as power of 2.
* 2. 28. .30 - arithmetic operation which should be
* applied to previous value stored in
* uaddr2 . Values available ( from 2005 up to
* 2016 ) : SET . ADD , OR , ANDN , XOR .
* 3. 24. .29 - comparison operation which should be
* applied to the old value stored in uaddr2
* ( before arithmetic operation is applied ) .
* Possible values : EQ , NE , LT , LE , GT , GE .
* 4. 12. .23 - Second operand for arithmetic operation .
* If bit 31 is set , it is interpreted as
* power of 2.
* 5. 00. .11 - Value against which old value stored in
* uaddr2 is compared .
*/
static const struct {
uint32_t val ;
const char * str ;
int err ;
const char * errstr ;
} wake_ops [ ] = {
2016-11-27 18:07:36 +03:00
{ 0x00000000 , " FUTEX_OP_SET<<28|0<<12|FUTEX_OP_CMP_EQ<<24|0 " } ,
{ 0x00fff000 , " FUTEX_OP_SET<<28|0xfff<<12|FUTEX_OP_CMP_EQ<<24| "
" 0 " } ,
{ 0x00000fff , " FUTEX_OP_SET<<28|0<<12|FUTEX_OP_CMP_EQ<<24| "
" 0xfff " } ,
{ 0x00ffffff , " FUTEX_OP_SET<<28|0xfff<<12|FUTEX_OP_CMP_EQ<<24| "
" 0xfff " } ,
{ 0x10000000 , " FUTEX_OP_ADD<<28|0<<12|FUTEX_OP_CMP_EQ<<24|0 " } ,
{ 0x20000000 , " FUTEX_OP_OR<<28|0<<12|FUTEX_OP_CMP_EQ<<24|0 " } ,
{ 0x30000000 , " FUTEX_OP_ANDN<<28|0<<12|FUTEX_OP_CMP_EQ<<24|0 " } ,
{ 0x40000000 , " FUTEX_OP_XOR<<28|0<<12|FUTEX_OP_CMP_EQ<<24|0 " } ,
{ 0x50000000 , " 0x5<<28 /* FUTEX_OP_??? */|0<<12| "
" FUTEX_OP_CMP_EQ<<24|0 " , ENOSYS , " ENOSYS " } ,
{ 0x70000000 , " 0x7<<28 /* FUTEX_OP_??? */|0<<12| "
" FUTEX_OP_CMP_EQ<<24|0 " , ENOSYS , " ENOSYS " } ,
{ 0x80000000 , " FUTEX_OP_OPARG_SHIFT<<28|FUTEX_OP_SET<<28|0<<12| "
" FUTEX_OP_CMP_EQ<<24|0 " } ,
{ 0xa0caffee , " FUTEX_OP_OPARG_SHIFT<<28|FUTEX_OP_OR<<28| "
" 0xcaf<<12|FUTEX_OP_CMP_EQ<<24|0xfee " } ,
{ 0x01000000 , " FUTEX_OP_SET<<28|0<<12|FUTEX_OP_CMP_NE<<24|0 " } ,
{ 0x01234567 , " FUTEX_OP_SET<<28|0x234<<12|FUTEX_OP_CMP_NE<<24| "
" 0x567 " } ,
{ 0x02000000 , " FUTEX_OP_SET<<28|0<<12|FUTEX_OP_CMP_LT<<24|0 " } ,
{ 0x03000000 , " FUTEX_OP_SET<<28|0<<12|FUTEX_OP_CMP_LE<<24|0 " } ,
{ 0x04000000 , " FUTEX_OP_SET<<28|0<<12|FUTEX_OP_CMP_GT<<24|0 " } ,
{ 0x05000000 , " FUTEX_OP_SET<<28|0<<12|FUTEX_OP_CMP_GE<<24|0 " } ,
{ 0x06000000 , " FUTEX_OP_SET<<28|0<<12| "
" 0x6<<24 /* FUTEX_OP_CMP_??? */|0 " , ENOSYS , " ENOSYS " } ,
{ 0x07000000 , " FUTEX_OP_SET<<28|0<<12| "
" 0x7<<24 /* FUTEX_OP_CMP_??? */|0 " , ENOSYS , " ENOSYS " } ,
{ 0x08000000 , " FUTEX_OP_SET<<28|0<<12| "
" 0x8<<24 /* FUTEX_OP_CMP_??? */|0 " , ENOSYS , " ENOSYS " } ,
{ 0x0f000000 , " FUTEX_OP_SET<<28|0<<12| "
" 0xf<<24 /* FUTEX_OP_CMP_??? */|0 " , ENOSYS , " ENOSYS " } ,
{ 0xbadfaced , " FUTEX_OP_OPARG_SHIFT<<28|FUTEX_OP_ANDN<<28| "
" 0xdfa<<12|0xa<<24 /* FUTEX_OP_CMP_??? */|0xced " ,
2016-08-30 16:30:37 +03:00
ENOSYS , " ENOSYS " } ,
2016-11-27 18:07:36 +03:00
{ 0xffffffff , " FUTEX_OP_OPARG_SHIFT<<28| "
" 0x7<<28 /* FUTEX_OP_??? */|0xfff<<12| "
" 0xf<<24 /* FUTEX_OP_CMP_??? */|0xfff " ,
2016-08-30 16:30:37 +03:00
ENOSYS , " ENOSYS " } ,
} ;
for ( i = 0 ; i < ARRAY_SIZE ( wake_ops ) ; i + + ) {
for ( j = 0 ; j < 2 ; j + + ) {
CHECK_FUTEX_ENOSYS ( uaddr ,
j ? FUTEX_WAKE_OP_PRIVATE : FUTEX_WAKE_OP ,
VAL , i , uaddr2 , wake_ops [ i ] . val , ( rc = = 0 ) ) ;
printf ( " futex(%p, FUTEX_WAKE_OP%s, %u, %u, %p, %s) = "
" %s \n " , uaddr , j ? " _PRIVATE " : " " , VAL_PR , i ,
2016-09-02 18:25:35 +03:00
uaddr2 , wake_ops [ i ] . str , sprintrc ( rc ) ) ;
2016-08-30 16:30:37 +03:00
}
}
CHECK_INVALID_CLOCKRT ( FUTEX_WAKE_OP , ARG3 | ARG4 | ARG5 | ARG6 ,
" %u " , " %u " , " %#lx " ,
/* Decoding of the 0xdeadbee4 value */
2016-11-27 18:07:36 +03:00
" FUTEX_OP_OPARG_SHIFT<<28|0x5<<28 /* FUTEX_OP_??? */|0xadb<<12| "
" 0xe<<24 /* FUTEX_OP_CMP_??? */|0xee4 " ) ;
2016-08-30 16:30:37 +03:00
/* FUTEX_LOCK_PI - slow path for mutex lock with process inheritance
* support . Expect that futex has 0 in unlocked case and
* TID of owning process in locked case . Value can also
* contain FUTEX_WAITERS bit signalling the presence of
* waiters queue .
* Possible flags : PRIVATE
* 1. uaddr - futex address
* 2. op - FUTEX_LOCK_PI
* 3. val - not used
* 4. timeout - timeout
* 5. uaddr2 - not used
* 6. val3 - not used
*/
* uaddr = getpid ( ) ;
CHECK_FUTEX_ENOSYS ( uaddr + 1 , FUTEX_LOCK_PI , VAL , tmout , uaddr2 + 1 ,
VAL3 , ( rc = = - 1 ) & & ( errno = = EFAULT ) ) ;
2016-11-25 00:48:00 +03:00
printf ( " futex(%p, FUTEX_LOCK_PI, {tv_sec=%jd, tv_nsec=%jd}) = %s \n " ,
2016-09-15 23:04:07 +03:00
uaddr + 1 , ( intmax_t ) tmout - > tv_sec , ( intmax_t ) tmout - > tv_nsec ,
2016-09-02 18:25:35 +03:00
sprintrc ( rc ) ) ;
2016-08-30 16:30:37 +03:00
CHECK_FUTEX_ENOSYS ( uaddr + 1 , FUTEX_PRIVATE_FLAG | FUTEX_LOCK_PI , VAL ,
tmout , uaddr2 + 1 , VAL3 , ( rc = = - 1 ) & & ( errno = = EFAULT ) ) ;
2016-11-25 00:48:00 +03:00
printf ( " futex(%p, FUTEX_LOCK_PI_PRIVATE, {tv_sec=%jd, tv_nsec=%jd}) = "
" %s \n " ,
2016-09-15 23:04:07 +03:00
uaddr + 1 , ( intmax_t ) tmout - > tv_sec , ( intmax_t ) tmout - > tv_nsec ,
2016-09-02 18:25:35 +03:00
sprintrc ( rc ) ) ;
2016-08-30 16:30:37 +03:00
/* NULL is passed by invalid_op() in cases valid timeout address is
* needed */
CHECK_INVALID_CLOCKRT ( FUTEX_LOCK_PI , ARG4 , " NULL " ) ;
/* FUTEX_UNLOCK_PI - slow path for mutex unlock with process inheritance
* support . Expected to be called by process in case
* it failed to execute fast path ( it usually means
* that FUTEX_WAITERS flag had been set while the lock
* has been held ) .
* Possible flags : PRIVATE
* 1. uaddr - futex address
* 2. op - FUTEX_UNLOCK_PI
* 3. val - not used
* 4. timeout - not used
* 5. uaddr2 - not used
* 6. val3 - not used
*/
CHECK_FUTEX_ENOSYS ( uaddr + 1 , FUTEX_UNLOCK_PI , VAL , tmout , uaddr2 + 1 ,
VAL3 , ( rc = = - 1 ) & & ( errno = = EFAULT ) ) ;
2016-09-02 18:25:35 +03:00
printf ( " futex(%p, FUTEX_UNLOCK_PI) = %s \n " , uaddr + 1 , sprintrc ( rc ) ) ;
2016-08-30 16:30:37 +03:00
CHECK_FUTEX_ENOSYS ( uaddr + 1 , FUTEX_PRIVATE_FLAG | FUTEX_UNLOCK_PI , VAL ,
tmout , uaddr2 + 1 , VAL3 , ( rc = = - 1 ) & & ( errno = = EFAULT ) ) ;
printf ( " futex(%p, FUTEX_UNLOCK_PI_PRIVATE) = %s \n " , uaddr + 1 ,
2016-09-02 18:25:35 +03:00
sprintrc ( rc ) ) ;
2016-08-30 16:30:37 +03:00
CHECK_INVALID_CLOCKRT ( FUTEX_UNLOCK_PI , 0 ) ;
/* FUTEX_TRYLOCK_PI - slow path for mutex trylock with process
* inheritance support .
* Possible flags : PRIVATE
* 1. uaddr - futex address
* 2. op - FUTEX_TRYLOCK_PI
* 3. val - not used
* 4. timeout - not used
* 5. uaddr2 - not used
* 6. val3 - not used
*/
CHECK_FUTEX_ENOSYS ( uaddr + 1 , FUTEX_TRYLOCK_PI , VAL , tmout , uaddr2 + 1 ,
VAL3 , ( rc = = - 1 ) & & ( errno = = EFAULT ) ) ;
2016-09-02 18:25:35 +03:00
printf ( " futex(%p, FUTEX_TRYLOCK_PI) = %s \n " , uaddr + 1 , sprintrc ( rc ) ) ;
2016-08-30 16:30:37 +03:00
CHECK_FUTEX_ENOSYS ( uaddr + 1 , FUTEX_PRIVATE_FLAG | FUTEX_TRYLOCK_PI ,
VAL , tmout , uaddr2 + 1 , VAL3 , ( rc = = - 1 ) & & ( errno = = EFAULT ) ) ;
printf ( " futex(%p, FUTEX_TRYLOCK_PI_PRIVATE) = %s \n " , uaddr + 1 ,
2016-09-02 18:25:35 +03:00
sprintrc ( rc ) ) ;
2016-08-30 16:30:37 +03:00
CHECK_INVALID_CLOCKRT ( FUTEX_TRYLOCK_PI , 0 ) ;
/* FUTEX_WAIT_REQUEUE_PI - kernel-side handling of special case when
* processes should be re - queued on PI - aware
* futexes . This is so special since PI futexes
* utilize rt_mutex and it should be at no time
* left free with a wait queue , so this should
* be performed atomically in - kernel .
* Possible flags : PRIVATE , CLOCKRT
* 1. uaddr - futex address
* 2. op - FUTEX_WAIT_REQUEUE_PI
* 3. val - expected value stored in uaddr
* 4. timeout - timeout
* 5. uaddr2 - ( PI - aware ) futex address to requeue process on
* 6. val3 - not used ( in kernel , it always initialized to
* FUTEX_BITSET_MATCH_ANY and passed to
* futex_wait_requeue_pi ( ) )
*/
CHECK_FUTEX_ENOSYS ( uaddr , FUTEX_WAIT_REQUEUE_PI , VAL , tmout , uaddr2 ,
VAL3 , ( rc = = - 1 ) & & ( errno = = EAGAIN ) ) ;
2016-11-25 00:48:00 +03:00
printf ( " futex(%p, FUTEX_WAIT_REQUEUE_PI, %u, "
" {tv_sec=%jd, tv_nsec=%jd}, %p) = %s \n " ,
2016-09-15 23:04:07 +03:00
uaddr , VAL_PR , ( intmax_t ) tmout - > tv_sec ,
( intmax_t ) tmout - > tv_nsec , uaddr2 , sprintrc ( rc ) ) ;
2016-08-30 16:30:37 +03:00
CHECK_FUTEX_ENOSYS ( uaddr , FUTEX_PRIVATE_FLAG | FUTEX_WAIT_REQUEUE_PI ,
VAL , tmout , uaddr2 , VAL3 , ( rc = = - 1 ) & & ( errno = = EAGAIN ) ) ;
2016-11-25 00:48:00 +03:00
printf ( " futex(%p, FUTEX_WAIT_REQUEUE_PI_PRIVATE, %u, "
" {tv_sec=%jd, tv_nsec=%jd}, %p) "
2016-09-15 23:04:07 +03:00
" = %s \n " , uaddr , VAL_PR , ( intmax_t ) tmout - > tv_sec ,
( intmax_t ) tmout - > tv_nsec , uaddr2 , sprintrc ( rc ) ) ;
2016-08-30 16:30:37 +03:00
CHECK_FUTEX_ENOSYS ( uaddr , FUTEX_CLOCK_REALTIME | FUTEX_WAIT_REQUEUE_PI ,
VAL , tmout , uaddr2 , VAL3 , ( rc = = - 1 ) & & ( errno = = EAGAIN ) ) ;
printf ( " futex(%p, FUTEX_WAIT_REQUEUE_PI|FUTEX_CLOCK_REALTIME, %u, "
2016-11-25 00:48:00 +03:00
" {tv_sec=%jd, tv_nsec=%jd}, %p) = %s \n " , uaddr , VAL_PR ,
2016-09-15 23:04:07 +03:00
( intmax_t ) tmout - > tv_sec , ( intmax_t ) tmout - > tv_nsec , uaddr2 ,
2016-09-02 18:25:35 +03:00
sprintrc ( rc ) ) ;
2016-08-30 16:30:37 +03:00
CHECK_FUTEX_ENOSYS ( uaddr , FUTEX_CLOCK_REALTIME | FUTEX_PRIVATE_FLAG |
FUTEX_WAIT_REQUEUE_PI , VAL , tmout , uaddr2 , VAL3 ,
( rc = = - 1 ) & & ( errno = = EAGAIN ) ) ;
printf ( " futex(%p, FUTEX_WAIT_REQUEUE_PI_PRIVATE|FUTEX_CLOCK_REALTIME, "
2016-11-25 00:48:00 +03:00
" %u, {tv_sec=%jd, tv_nsec=%jd}, %p) = %s \n " , uaddr , VAL_PR ,
2016-09-15 23:04:07 +03:00
( intmax_t ) tmout - > tv_sec , ( intmax_t ) tmout - > tv_nsec , uaddr2 ,
2016-09-02 18:25:35 +03:00
sprintrc ( rc ) ) ;
2016-08-30 16:30:37 +03:00
/* FUTEX_CMP_REQUEUE_PI - version of FUTEX_CMP_REQUEUE which re-queues
* on PI - aware futex .
* Possible flags : PRIVATE
* 1. uaddr - futex address
* 2. op - FUTEX_CMP_REQUEUE
* 3. val - how many processes to wake
* 4. val2 - amount of processes to re - queue on uadr2
* 5. uaddr2 - ( PI - aware ) futex address , to re - queue waiting processes
* on
* 6. val3 - expected value stored in uaddr
*/
/* All these should fail with EINVAL since we try to re-queue to non-PI
* futex .
*/
CHECK_FUTEX_ENOSYS ( uaddr , FUTEX_CMP_REQUEUE_PI , VAL , VAL2 , uaddr2 , VAL3 ,
( rc = = - 1 ) & & ( errno = = EINVAL ) ) ;
printf ( " futex(%p, FUTEX_CMP_REQUEUE_PI, %u, %u, %p, %u) = %s \n " ,
2016-09-02 18:25:35 +03:00
uaddr , VAL_PR , VAL2_PR , uaddr2 , VAL3_PR , sprintrc ( rc ) ) ;
2016-08-30 16:30:37 +03:00
CHECK_FUTEX_ENOSYS ( uaddr , FUTEX_CMP_REQUEUE_PI , VAL , VAL2 , uaddr2 ,
* uaddr , ( rc = = - 1 ) & & ( errno = = EINVAL ) ) ;
printf ( " futex(%p, FUTEX_CMP_REQUEUE_PI, %u, %u, %p, %u) = %s \n " ,
2016-09-02 18:25:35 +03:00
uaddr , VAL_PR , VAL2_PR , uaddr2 , * uaddr , sprintrc ( rc ) ) ;
2016-08-30 16:30:37 +03:00
CHECK_FUTEX_ENOSYS ( uaddr , FUTEX_PRIVATE_FLAG | FUTEX_CMP_REQUEUE_PI ,
VAL , VAL2 , uaddr2 , * uaddr , ( rc = = - 1 ) & & ( errno = = EINVAL ) ) ;
printf ( " futex(%p, FUTEX_CMP_REQUEUE_PI_PRIVATE, %u, %u, %p, %u) = %s \n " ,
2016-09-02 18:25:35 +03:00
uaddr , VAL_PR , VAL2_PR , uaddr2 , * uaddr , sprintrc ( rc ) ) ;
2016-08-30 16:30:37 +03:00
CHECK_INVALID_CLOCKRT ( FUTEX_CMP_REQUEUE_PI , ARG3 | ARG4 | ARG5 | ARG6 ,
" %u " , " %u " , " %#lx " , " %u " ) ;
/*
* Unknown commands
*/
CHECK_FUTEX ( uaddr , 0xd , VAL , tmout + 1 , uaddr2 + 1 , VAL3 ,
( rc = = - 1 ) & & ( errno = = ENOSYS ) ) ;
printf ( " futex(%p, 0xd /* FUTEX_??? */, %u, %p, %p, %#x) = %s \n " ,
2016-09-02 18:25:35 +03:00
uaddr , VAL_PR , tmout + 1 , uaddr2 + 1 , VAL3_PR , sprintrc ( rc ) ) ;
2016-08-30 16:30:37 +03:00
CHECK_FUTEX ( uaddr , 0xbefeeded , VAL , tmout + 1 , uaddr2 , VAL3 ,
( rc = = - 1 ) & & ( errno = = ENOSYS ) ) ;
printf ( " futex(%p, 0xbefeeded /* FUTEX_??? */, %u, %p, %p, %#x) = %s \n " ,
2016-09-02 18:25:35 +03:00
uaddr , VAL_PR , tmout + 1 , uaddr2 , VAL3_PR , sprintrc ( rc ) ) ;
2016-08-30 16:30:37 +03:00
puts ( " +++ exited with 0 +++ " ) ;
return 0 ;
}
# else
SKIP_MAIN_UNDEFINED ( " __NR_futex " )
# endif