/*
 * libk/utils.h - useful functions for the kernel
 * 
 * Copyright (c) 2015 UPMC Sorbonne Universites
 *
 * This file is part of ALMOS-kernel.
 *
 * ALMOS-kernel is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2.0 of the License.
 *
 * ALMOS-kernel is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with ALMOS-kernel; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 */

#ifndef _UTILS_H_
#define _UTILS_H_

#include <types.h>

struct kernel_iter_s {
        cid_t cid;
};

struct kernel_iter_s kernel_list;

/* return the substration of two uint_t  while avoid	*
 * the overflow case. Big is normally bigger than small.*/
#if 0
static uint_t uint_subwo(uint_t big, uint_t small)
{
	if(big >= small)
		return (long)big - (long)small;
	else	/* big has overflowed */
		return (UINT32_MAX - small) + big;
}
#else
#define uint_subwo(big, small)				\
({							\
	uint_t __ret;					\
	if(big >= small)				\
		__ret = big - small;			\
	else	/* big has overflowed */		\
		__ret = (UINT32_MAX - small) + big;	\
	__ret;						\
})
#endif

/* The number of kernel running on the platform (some clusters does not have
 * a kernel, like the I/O cluster.
 */
#define  KERNEL_TOTAL_NR         current_cluster->clstr_wram_nr

/* From Linux */
#define container_of(ptr, type, member) ({                              \
        const typeof( ((type *)0)->member ) *__mptr = (ptr);            \
                (type *)( (char *)__mptr - offsetof(type,member) );})

/* Assuming that all running kernels are contiguously in cluster 0,1,2 etc...,
 * and empty cluster and I/O cluster are the two last. This is a very
 * dangerous assumption, but for now we can't do otherwise. It should be
 * marked as FIXME. This comment is also true for kernel_foreach_backward.
 */
#define kernel_foreach(iter, next)                              \
        iter = &kernel_list;                                    \
        next = 0;                                               \
        for ( iter->cid = 0; iter->cid < KERNEL_TOTAL_NR;       \
                        iter->cid++, next = iter->cid )

/* cid_t is an unsigned int16_t and CID_NULL == (cid_t)-1 == 65535. When the
 * loop is doing 0-1, it's equal to 65535, and so equal to CID_NULL, that's
 * why this is the end loop condition.
 * 
 * You are not expected to understand this.
 *
 */
#define kernel_foreach_backward_init(iter,next)                 \
        iter = &kernel_list;                                    \
        next = KERNEL_TOTAL_NR-1;

#define kernel_foreach_backward(iter, next)                     \
        kernel_foreach_backward_init(iter,next)                 \
        for ( iter->cid = KERNEL_TOTAL_NR-1;                    \
                        iter->cid != CID_NULL;                  \
                        iter->cid--, next = iter->cid )

#endif /* _UTILS_H_ */
