/* SPDX-License-Identifier: GPL-2.0-only */

#ifndef __LINUX_HUNG_TASK_H
#define __LINUX_HUNG_TASK_H

#include <linux/bug.h>
#include <linux/sched.h>
#include <linux/compiler.h>


#define BLOCKER_TYPE_MUTEX		0x00UL
#define BLOCKER_TYPE_SEM		0x01UL
#define BLOCKER_TYPE_RWSEM_READER	0x02UL
#define BLOCKER_TYPE_RWSEM_WRITER	0x03UL

#define BLOCKER_TYPE_MASK		0x03UL

#ifdef CONFIG_DETECT_HUNG_TASK_BLOCKER
static inline void hung_task_set_blocker(void *lock, unsigned long type)
{
	unsigned long lock_ptr = (unsigned long)lock;

	WARN_ON_ONCE(!lock_ptr);
	WARN_ON_ONCE(READ_ONCE(current->blocker));

	
	if (lock_ptr & BLOCKER_TYPE_MASK)
		return;

	WRITE_ONCE(current->blocker, lock_ptr | type);
}

static inline void hung_task_clear_blocker(void)
{
	WRITE_ONCE(current->blocker, 0UL);
}


static inline unsigned long hung_task_get_blocker_type(unsigned long blocker)
{
	WARN_ON_ONCE(!blocker);

	return blocker & BLOCKER_TYPE_MASK;
}

static inline void *hung_task_blocker_to_lock(unsigned long blocker)
{
	WARN_ON_ONCE(!blocker);

	return (void *)(blocker & ~BLOCKER_TYPE_MASK);
}
#else
static inline void hung_task_set_blocker(void *lock, unsigned long type)
{
}
static inline void hung_task_clear_blocker(void)
{
}
static inline unsigned long hung_task_get_blocker_type(unsigned long blocker)
{
	return 0UL;
}
static inline void *hung_task_blocker_to_lock(unsigned long blocker)
{
	return NULL;
}
#endif

#endif 
