/* Copyright (c) 2019-2024 Griefer@Work                                       *
 *                                                                            *
 * This software is provided 'as-is', without any express or implied          *
 * warranty. In no event will the authors be held liable for any damages      *
 * arising from the use of this software.                                     *
 *                                                                            *
 * Permission is granted to anyone to use this software for any purpose,      *
 * including commercial applications, and to alter it and redistribute it     *
 * freely, subject to the following restrictions:                             *
 *                                                                            *
 * 1. The origin of this software must not be misrepresented; you must not    *
 *    claim that you wrote the original software. If you use this software    *
 *    in a product, an acknowledgement (see the following) in the product     *
 *    documentation is required:                                              *
 *    Portions Copyright (c) 2019-2024 Griefer@Work                           *
 * 2. Altered source versions must be plainly marked as such, and must not be *
 *    misrepresented as being the original software.                          *
 * 3. This notice may not be removed or altered from any source distribution. *
 */
#ifndef __GUARD_HYBRID_SCHED___GETTID_H
#define __GUARD_HYBRID_SCHED___GETTID_H 1

#include <__stdinc.h>

#include <hybrid/host.h>

#ifdef __KOS__
#ifdef __KERNEL__
#ifndef __KOS_VERSION__
#define __KOS_VERSION__ 200 /* Legacy model. */
#endif /* !__KOS_VERSION__ */

#if __KOS_VERSION__ >= 400
#include <sched/pertask.h> /* THIS_TASK */
#elif __KOS_VERSION__ >= 300
#include <sched/task.h>   /* THIS_TASK */
#else /* __KOS_VERSION__ >= ... */
#include <sched/percpu.h> /* THIS_TASK */
#endif /* __KOS_VERSION__ < ... */
#define __HYBRID_SIZEOF_TID__ __SIZEOF_POINTER__
#define __HYBRID_GETTID_INVALID_IS_ZERO
#define __HYBRID_GETTID_INVALID       __NULLPTR
#define __HYBRID_GETTID_PRINTF_FMT    "%p"
#define __HYBRID_GETTID_PRINTF_ARG(x) x
#ifdef __CC__
#define __hybrid_gettid() THIS_TASK
#define __hybrid_tid_t    struct task *
#endif /* __CC__ */

#else /* __KERNEL__ */
#if ((__KOS_VERSION__ >= 400) && \
     (defined(__x86_64__) || defined(__i386__)))
#include <asm/intrin.h>

/* Use the ELF thread-self pointer! */
#define __hybrid_tid_t void *
#ifdef __x86_64__
#define __hybrid_gettid() __rdfsptr(0)
#else /* __x86_64__ */
#define __hybrid_gettid() __rdgsptr(0)
#endif /* !__x86_64__ */
#define __HYBRID_SIZEOF_TID__           __SIZEOF_POINTER__
#define __HYBRID_GETTID_PRINTF_FMT      "%p"
#define __HYBRID_GETTID_PRINTF_ARG(x)   (void *)(x)
#define __HYBRID_GETTID_INVALID_IS_ZERO
#define __HYBRID_GETTID_INVALID 0

#elif __KOS_VERSION__ >= 400 && defined(__arm__)
#include <hybrid/typecore.h>
#include <kos/asm/kuser.h>
#define __hybrid_tid_t                void *
#define __hybrid_gettid()             __kuser_get_tls()
#define __HYBRID_SIZEOF_TID__         __SIZEOF_POINTER__
#define __HYBRID_GETTID_INVALID       __NULLPTR
#define __HYBRID_GETTID_PRINTF_FMT    "%p"
#define __HYBRID_GETTID_PRINTF_ARG(x) (void *)(x)
#define __HYBRID_GETTID_INVALID_IS_ZERO
#else /* Mk4 + X86 */
#include <__crt.h>

#include <bits/types.h>

#define __HYBRID_SIZEOF_TID__ __SIZEOF_PID_T__
#if 1 /* PID=0 should never be valid */
#define __HYBRID_GETTID_INVALID_IS_ZERO
#define __HYBRID_GETTID_INVALID 0
#else
#define __HYBRID_GETTID_INVALID (-1)
#endif
#define __hybrid_gettid __hybrid_gettid
#ifdef __CC__
#define __hybrid_tid_t __pid_t
#if !defined(__gettid_defined) && !defined(gettid)
#define __gettid_defined
__DECL_BEGIN
__CREDIRECT(__ATTR_CONST,__pid_t,__NOTHROW,__hybrid_gettid,(void),gettid,())
__DECL_END
#endif /* !__gettid_defined && !gettid */
#endif /* __CC__ */
#endif /* ... */
#endif /* !__KERNEL__ */
#elif defined(__arm__) && (defined(__KOS__) || defined(__linux__))
#define __hybrid_tid_t                void *
#define __hybrid_gettid()             ((*(__ATTR_PURE_T __ATTR_WUNUSED_T void *(*)(void))0xffff0fe0)())
#define __HYBRID_SIZEOF_TID__         4
#define __HYBRID_GETTID_INVALID       __NULLPTR
#define __HYBRID_GETTID_PRINTF_FMT    "%p"
#define __HYBRID_GETTID_PRINTF_ARG(x) (void *)(x)
#define __HYBRID_GETTID_INVALID_IS_ZERO
#elif defined(__WINNT__)
#if defined(__NO_has_include) || __has_include(<intrin.h>)
#include <intrin.h>
/* Use the fs/gs self-pointer as TID field. */
#if defined(__x86_64__)
#define __HYBRID_SIZEOF_TID__ 8
#define __hybrid_gettid()     (void *)__readgsqword(0x30)
#elif defined(__i386__)
#define __HYBRID_SIZEOF_TID__ 4
#define __hybrid_gettid()     (void *)__readfsdword(0x18)
#endif /* ... */
#endif /* __has_include(<intrin.h>) */

#define __HYBRID_GETTID_INVALID_IS_ZERO
#ifdef __hybrid_gettid
#define __hybrid_tid_t          void *
#define __HYBRID_GETTID_INVALID __NULLPTR
#else /* __hybrid_gettid */
#define __HYBRID_GETTID_INVALID 0
#define __HYBRID_SIZEOF_TID__ 4
#ifdef __CC__
#include <hybrid/typecore.h>
#ifdef _MSC_VER
#pragma warning(disable: 4565) /* Needs to be kept off to prevent bogus warning if <Windows.h> re-declares `GetCurrentThreadId()' without `ATTR_CONST' */
#pragma warning(push)
#pragma warning(disable: 4559) /* Suppress warning about our addition of `ATTR_CONST' */
#endif /* _MSC_VER */
__DECL_BEGIN
#define __hybrid_tid_t __ULONG32_TYPE__
extern __ATTR_CONST __ATTR_DLLIMPORT __ULONG32_TYPE__ (__ATTR_STDCALL GetCurrentThreadId)(void);
__DECL_END
#ifdef _MSC_VER
#pragma warning(pop)
#endif /* !_MSC_VER */
#endif /* __CC__ */
#define __hybrid_gettid GetCurrentThreadId
#endif /* !__hybrid_gettid */
#elif __has_include(<errno.h>) || (defined(__unix__) && defined(__NO_has_include))
/* Posix requires that `errno' be thread-local, so we can just use its address as a TID */
#include <errno.h>
#define __HYBRID_SIZEOF_TID__   __SIZEOF_POINTER__
#define __hybrid_tid_t          void *
#define __hybrid_gettid()       ((void *)&errno)
#define __HYBRID_GETTID_INVALID __NULLPTR
#define __HYBRID_GETTID_INVALID_IS_ZERO
#elif (__has_include(<unistd.h>) || \
       (defined(__unix__) && defined(__NO_has_include)))
#include <unistd.h>
#if ((defined(SYS_gettid) || defined(__NR_gettid)) &&  \
     !(defined(gettid) || defined(__gettid_defined) || \
       defined(__gettid) || defined(____gettid_defined)))
#ifdef __SIZEOF_PID_T__
#define __HYBRID_SIZEOF_TID__ __SIZEOF_PID_T__
#elif defined(__SIZEOF_PID_T)
#define __HYBRID_SIZEOF_TID__ __SIZEOF_PID_T
#else /* ... */
#define __HYBRID_SIZEOF_TID__ __SIZEOF_INT__
__STATIC_ASSERT_MSG(sizeof(pid_t) == __HYBRID_SIZEOF_TID__, "Please adjust");
#endif /* !... */
#define __hybrid_tid_t pid_t
#ifdef __NR_gettid
#define __hybrid_gettid() syscall(__NR_gettid)
#else /* __NR_gettid */
#define __hybrid_gettid() syscall(SYS_gettid)
#endif /* !__NR_gettid */
#define __HYBRID_GETTID_INVALID_IS_ZERO
#define __HYBRID_GETTID_INVALID 0
#endif /* SYS_gettid || __NR_gettid */
#endif /* ... */


#ifndef __hybrid_gettid
#if (defined(gettid) || defined(__gettid_defined) || \
     defined(__gettid) || defined(____gettid_defined))
#ifdef __SIZEOF_PID_T__
#define __HYBRID_SIZEOF_TID__ __SIZEOF_PID_T__
#elif defined(__SIZEOF_PID_T)
#define __HYBRID_SIZEOF_TID__ __SIZEOF_PID_T
#else /* ... */
#define __HYBRID_SIZEOF_TID__ __SIZEOF_INT__
__STATIC_ASSERT_MSG(sizeof(pid_t) == __HYBRID_SIZEOF_TID__, "Please adjust");
#endif /* !... */
#define __hybrid_tid_t pid_t
#if defined(gettid) || defined(__gettid_defined)
#define __hybrid_gettid gettid
#else /* gettid || __gettid_defined */
#define __hybrid_gettid __gettid
#endif /* !gettid && !__gettid_defined */
#define __HYBRID_GETTID_INVALID_IS_ZERO
#define __HYBRID_GETTID_INVALID 0
#elif (__has_include(<pthread.h>) || \
       (defined(__NO_has_include) && \
        (defined(__unix__) || defined(__unix) || defined(unix))))
/* Use Posix thread handles as current-thread TID basis */
#include <pthread.h>
#ifdef __SIZEOF_PTHREAD_T__
#define __HYBRID_SIZEOF_TID__ __SIZEOF_PTHREAD_T__
#elif defined(__SIZEOF_PTHREAD_T)
#define __HYBRID_SIZEOF_TID__ __SIZEOF_PTHREAD_T
#else /* ... */
#include <hybrid/typecore.h>
#define __HYBRID_SIZEOF_TID__ __SIZEOF_POINTER__
__STATIC_ASSERT_MSG(sizeof(pthread_t) == __HYBRID_SIZEOF_TID__, "Please adjust");
#endif /* !... */
#define __hybrid_tid_t  pthread_t
#define __hybrid_gettid pthread_self
#define __HYBRID_GETTID_INVALID_IS_ZERO /* Not always, but good enough? */
#define __HYBRID_GETTID_INVALID (__CCAST(pthread_t) 0)
#define __hybrid_gettid_equal   pthread_equal
#elif (__has_include(<threads.h>) ||                                  \
       (defined(__NO_has_include) && !defined(__STDC_NO_THREADS__) && \
        defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L))
/* Use ISO C11 thread handles as current-thread TID basis */
#include <threads.h>
#ifdef __SIZEOF_THRD_T__
#define __HYBRID_SIZEOF_TID__ __SIZEOF_THRD_T__
#elif defined(__SIZEOF_THRD_T)
#define __HYBRID_SIZEOF_TID__ __SIZEOF_THRD_T
#elif defined(__SIZEOF_PTHREAD_T__)
#define __HYBRID_SIZEOF_TID__ __SIZEOF_PTHREAD_T__
#elif defined(__SIZEOF_PTHREAD_T)
#define __HYBRID_SIZEOF_TID__ __SIZEOF_PTHREAD_T
#else /* ... */
#include <hybrid/typecore.h>
#define __HYBRID_SIZEOF_TID__ __SIZEOF_POINTER__
__STATIC_ASSERT_MSG(sizeof(thrd_t) == __HYBRID_SIZEOF_TID__, "Please adjust");
#endif /* !... */
#define __hybrid_tid_t  thrd_t
#define __hybrid_gettid thrd_current
#define __HYBRID_GETTID_INVALID_IS_ZERO /* Not always, but good enough? */
#define __HYBRID_GETTID_INVALID (__CCAST(thrd_t)0)
#define __hybrid_gettid_equal   thrd_equal
#else /* ... */
/* Fallback: Assume single-threaded and assign  TID=0
 * for <invalid-tid> and TID=1 for the main() thread. */
#include <hybrid/typecore.h>
#define __HYBRID_SIZEOF_TID__ __SIZEOF_INT__
#define __HYBRID_GETTID_INVALID_IS_ZERO
#define __HYBRID_GETTID_INVALID       0
#define __HYBRID_GETTID_PRINTF_FMT    "%u"
#define __HYBRID_GETTID_PRINTF_ARG(x) (unsigned int)(x)
#define __hybrid_tid_t                int
#define __hybrid_gettid()             1
#endif /* !... */
#endif /* !__hybrid_gettid */

#ifndef __HYBRID_GETTID_PRINTF_FMT
#include <hybrid/typecore.h>
#if __HYBRID_SIZEOF_TID__ == __SIZEOF_POINTER__
#define __HYBRID_GETTID_PRINTF_FMT "%p"
#define __HYBRID_GETTID_PRINTF_ARG (void const *)
#elif __HYBRID_SIZEOF_TID__ > __SIZEOF_POINTER__
#define __HYBRID_GETTID_PRINTF_FMT "%llx"
#define __HYBRID_GETTID_PRINTF_ARG (unsigned long long)
#elif __HYBRID_SIZEOF_TID__ <= __SIZEOF_INT__
#define __HYBRID_GETTID_PRINTF_FMT "%x"
#define __HYBRID_GETTID_PRINTF_ARG (unsigned int)
#elif __HYBRID_SIZEOF_TID__ == __SIZEOF_LONG__
#define __HYBRID_GETTID_PRINTF_FMT "%lx"
#define __HYBRID_GETTID_PRINTF_ARG (unsigned long)
#else /* __HYBRID_SIZEOF_TID__... */
#define __HYBRID_GETTID_PRINTF_FMT "%p"
#define __HYBRID_GETTID_PRINTF_ARG (void const *)
#endif /* !__HYBRID_SIZEOF_TID__... */
#endif /* !__HYBRID_GETTID_PRINTF_FMT */


#ifndef __hybrid_gettid_equal
#define __hybrid_gettid_equal(a, b) ((a) == (b))
#endif /* !__hybrid_gettid_equal */

#ifndef __hybrid_gettid_iscaller
#define __hybrid_gettid_iscaller(tid) \
	__hybrid_gettid_equal(__hybrid_gettid(), tid)
#endif /* !__hybrid_gettid_iscaller */


#endif /* !__GUARD_HYBRID_SYNC_THREADID_H */
