/****************************************************************************
 * sched/os_internal.h
 *
 *   Copyright (C) 2007, 2008 Gregory Nutt. All rights reserved.
 *   Author: Gregory Nutt <spudmonkey@racsa.co.cr>
 *
 * 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. Neither the name NuttX nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "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
 * COPYRIGHT OWNER OR CONTRIBUTORS 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.
 *
 ****************************************************************************/

#ifndef __OS_INTERNAL_H
#define __OS_INTERNAL_H

/****************************************************************************
 * Included Files
 ****************************************************************************/

#include <queue.h>
#include <sched.h>
#include <nuttx/kmalloc.h>

/****************************************************************************
 * Definitions
 ****************************************************************************/

/* OS CRASH CODES */

enum os_crash_codes_e
{
  OSERR_NOERROR = 0,          /* No error */
  OSERR_NOTIMPLEMENTED,       /* Feature is not implemented */
  OSERR_INTERNAL,             /* Internal logic error */
  OSERR_UNEXPECTEDISR,        /* Received unexpected interrupt */
  OSERR_UNDEFINEDINSN,        /* Undefined instruction */
  OSERR_ERREXCEPTION,         /* Other CPU-detected errors */
  OSERR_OUTOFMEMORY,          /* Insufficient memory */
  OSERR_OUTOFMESSAGES,        /* Out of messages */
  OSERR_NOIDLETASK,           /* There is no idle task */
  OSERR_MQNONEMPTYCOUNT,      /* Expected waiter for non-empty queue */
  OSERR_MQNOTFULLCOUNT,       /* Expected waiter for non-full queue */
  OSERR_BADWAITSEM,           /* Already waiting for a semaphore */
  OSERR_BADMSGTYPE,           /* Tried to free a bad message type */
  OSERR_FAILEDTOADDSIGNAL,    /* Failed to add pending signal */
  OSERR_FAILEDTOREMOVESIGNAL, /* Failed to remove pending signal */
  OSERR_TIMEOUTNOTCB,         /* Timed out, but not TCB registered */
  OSERR_NOPENDINGSIGNAL,      /* Expected a signal to be pending */
  OSERR_BADDELETESTATE,       /* Bad state in task deletion */
  OSERR_WDOGNOTFOUND,         /* Active watchdog not found */
  OSERR_EXITFROMINTERRUPT,    /* Interrupt code attempted to exit */
  OSERR_BADUNBLOCKSTATE,      /* Attempt to unblock from bad state */
  OSERR_BADBLOCKSTATE,        /* Attempt to block from bad state */
  OSERR_BADREPRIORITIZESTATE  /* Attempt to reprioritize in bad state or priority */
};

/* Special task IDS */

#define NULL_TASK_PROCESS_ID 0
#define INVALID_PROCESS_ID   0

/* Although task IDs can take the (positive, non-zero)
 * range of pid_t, the number of tasks that will be supported
 * at any one time is (artificially) limited by the CONFIG_MAX_TASKS
 * configuration setting. Limiting the number of tasks speeds certain
 * OS functions (this is the only limitation in the number of
 * tasks built into the design).
 */

#define MAX_TASKS_MASK      (CONFIG_MAX_TASKS-1)
#define PIDHASH(pid)        ((pid) & MAX_TASKS_MASK)

/* Stubs used when there are no file descriptors */

#if CONFIG_NFILE_DESCRIPTORS <= 0 && CONFIG_NSOCKET_DESCRIPTORS <= 0
# define sched_setupidlefiles(t)    (OK)
# define sched_setuptaskfiles(t)    (OK)
# define sched_setuppthreadfiles(t) (OK)
# define sched_releasefiles(t)      (OK)
#endif

/* A more efficient ways to access the errno */

#define SET_ERRNO(e) \
  { _TCB *rtcb = _TCB*)g_readytorun.head; rtcb->pterrno = (e); }

#define _SET_TCB_ERRNO(t,e) \
  { (t)->pterrno = (e); }

/****************************************************************************
 * Public Type Definitions
 ****************************************************************************/

/* This structure defines the format of the hash table that
 * is used to (1) determine if a task ID is unique, and (2)
 * to map a process ID to its corresponding TCB.
 */

struct pidhash_s
{
  FAR _TCB *tcb;
  pid_t     pid;
};
typedef struct pidhash_s  pidhash_t;

/* This structure defines an element of the g_tasklisttable[].
 * This table is used to map a task_state enumeration to the
 * corresponding task list.
 */

struct tasklist_s
{
  DSEG volatile dq_queue_t *list; /* Pointer to the task list */
  boolean prioritized;            /* TRUE if the list is prioritized */
};
typedef struct tasklist_s tasklist_t;

/****************************************************************************
 * Global Variables
 ****************************************************************************/

/* Declared in os_start.c ***************************************************/

/* The state of a task is indicated both by the task_state field
 * of the TCB and by a series of task lists.  All of these
 * tasks lists are declared below. Although it is not always
 * necessary, most of these lists are prioritized so that common
 * list handling logic can be used (only the g_readytorun,
 * the g_pendingtasks, and the g_waitingforsemaphore lists need
 * to be prioritized).
 */

/* This is the list of all tasks that are ready to run.  The head
 * of this list is the currently active task; the tail of this
 * list is always the idle task.
 */

extern volatile dq_queue_t g_readytorun;

/* This is the list of all tasks that are ready-to-run, but
 * cannot be placed in the g_readytorun list because:  (1) They
 * are higher priority than the currently active task at the head
 * of the g_readytorun list, and (2) the currenly active task has
 * disabled pre-emption.
 */

extern volatile dq_queue_t g_pendingtasks;

/* This is the list of all tasks that are blocked waiting for a semaphore */

extern volatile dq_queue_t g_waitingforsemaphore;

/* This is the list of all tasks that are blocked waiting for a signal */

#ifndef CONFIG_DISABLE_SIGNALS
extern volatile dq_queue_t g_waitingforsignal;
#endif

/* This is the list of all tasks that are blocked waiting for a message
 * queue to become non-empty.
 */

#ifndef CONFIG_DISABLE_MQUEUE
extern volatile dq_queue_t g_waitingformqnotempty;
#endif

/* This is the list of all tasks that are blocked waiting for a message
 * queue to become non-full.
 */

#ifndef CONFIG_DISABLE_MQUEUE
extern volatile dq_queue_t g_waitingformqnotfull;
#endif

/* This the list of all tasks that have been initialized, but not yet
 * activated. NOTE:  This is the only list that is not prioritized.
 */

extern volatile dq_queue_t g_inactivetasks;

/* This is the list of dayed memory deallocations that need to be handled
 * within the IDLE loop.  These deallocations get queued by sched_free()
 * if the OS attempts to deallocate memory while it is within an interrupt
 * handler.
 */

extern volatile sq_queue_t g_delayeddeallocations;

/* This is the value of the last process ID assigned to a task */

extern volatile pid_t g_lastpid;

/* The following hash table is used for two things:
 *
 * 1. This hash table greatly speeds the determination of
 *    a new unique process ID for a task, and
 * 2. Is used to quickly map a process ID into a TCB.
 *
 * It has the side effects of using more memory and limiting
 * the number of tasks to CONFIG_MAX_TASKS.
 */

extern pidhash_t g_pidhash[CONFIG_MAX_TASKS];

/* This is a table of task lists.  This table is indexed by
 * the task state enumeration type (tstate_t) and provides
 * a pointer to the associated static task list (if there
 * is one) as well as a boolean indication as to if the list
 * is an ordered list or not.
 */

extern const tasklist_t g_tasklisttable[NUM_TASK_STATES];

/****************************************************************************
 * Public Function Prototypes
 ****************************************************************************/

extern void    task_start(void);
extern STATUS  task_schedsetup(FAR _TCB *tcb, int priority,
                               start_t start, main_t main);
extern STATUS  task_argsetup(FAR _TCB *tcb, const char *name,
                             const char *argv[]);
extern STATUS  task_deletecurrent(void);

extern boolean sched_addreadytorun(FAR _TCB *rtrtcb);
extern boolean sched_removereadytorun(FAR _TCB *rtrtcb);
extern boolean sched_addprioritized(FAR _TCB *newTcb,
                                    DSEG dq_queue_t *list);
extern boolean sched_mergepending(void);
extern void    sched_addblocked(FAR _TCB *btcb, tstate_t task_state);
extern void    sched_removeblocked(FAR _TCB *btcb);
extern FAR _TCB *sched_gettcb(pid_t pid);

#if CONFIG_NFILE_DESCRIPTORS > 0 || CONFIG_NSOCKET_DESCRIPTORS > 0
extern int     sched_setupidlefiles(FAR _TCB *tcb);
extern int     sched_setuptaskfiles(FAR _TCB *tcb);
extern int     sched_setuppthreadfiles(FAR _TCB *tcb);
#if CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_NFILE_STREAMS > 0
extern int     sched_setupstreams(FAR _TCB *tcb);
extern int     sched_flushfiles(FAR _TCB *tcb);
#endif
extern int     sched_releasefiles(FAR _TCB *tcb);
#endif

extern int     sched_releasetcb(FAR _TCB *tcb);

#endif /* __OS_INTERNAL_H */
