/*
 * Copyright (c) 2021-2022 The strace developers.
 * Copyright (c) 2021 André Almeida <andrealmeid@collabora.com>
 * All rights reserved.
 *
 * SPDX-License-Identifier: LGPL-2.1-or-later
 */

#include "defs.h"
#include <linux/futex.h>
#include "xlat/futex_waiter_flags.h"

struct print_waiter_data {
	unsigned int count;
};

static bool
print_waiter(struct tcb * const tcp, void * const elem_buf,
	     const size_t elem_size, void * const data)
{
	struct futex_waitv *waiter = elem_buf;
	struct print_waiter_data *p = data;

	if (p->count++ >= FUTEX_WAITV_MAX) {
		tprint_more_data_follows();
		return false;
	}

	tprint_struct_begin();
	PRINT_FIELD_X(*waiter, val);

	tprint_struct_next();
	PRINT_FIELD_ADDR64(*waiter, uaddr);

	tprint_struct_next();
	PRINT_FIELD_FLAGS(*waiter, flags, futex_waiter_flags, "FUTEX_???");

	if (waiter->__reserved) {
		tprint_struct_next();
		PRINT_FIELD_X(*waiter, __reserved);
	}

	tprint_struct_end();
	return true;
}

static void
print_waiter_array(struct tcb * const tcp, const kernel_ulong_t waiters,
		   const unsigned int nr_futexes)
{
	struct futex_waitv buf;
	struct print_waiter_data data = {};

	print_array(tcp, waiters, nr_futexes, &buf, sizeof(buf),
		    tfetch_mem, print_waiter, &data);
}

SYS_FUNC(futex_waitv)
{
	const kernel_ulong_t waiters = tcp->u_arg[0];
	const unsigned int nr_futexes = tcp->u_arg[1];
	const unsigned int flags = tcp->u_arg[2];
	const kernel_ulong_t timeout = tcp->u_arg[3];
	const unsigned int clockid = tcp->u_arg[4];

	print_waiter_array(tcp, waiters, nr_futexes);
	tprint_arg_next();
	PRINT_VAL_U(nr_futexes);
	tprint_arg_next();
	PRINT_VAL_X(flags);
	tprint_arg_next();
	print_timespec64(tcp, timeout);
	tprint_arg_next();
	printxval(clocknames, clockid, "CLOCK_???");

	return RVAL_DECODED;
}