/*
 * thread.h
 *
 * Copyright (C) 2018 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef _THREAD_H_
#define _THREAD_H_

#include <common.h>
#include <object.h>
#include <exception.h>
#include <sdk/list.h>
#include <lock.h>
#include <interrupt.h>
#include <syscalls.h>
#include <sdk/thread.h>

#define QUANTUM 30
#define MAX_THREADS 2097152
#define KERNEL_STACK_SIZE 262144

#define SAFE_EFLAGS_MASK 0x00000CD5

typedef enum
{
    WAIT_ALWAYS,
    WAIT_GROUP_ANY,
    WAIT_GROUP_ALL,
    WAIT_UNTIL_EQUAL,
    WAIT_UNTIL_NOT_EQUAL,
    WAIT_UNTIL_LESS,
    WAIT_UNTIL_NOT_LESS,
    WAIT_UNTIL_GREATER,
    WAIT_UNTIL_NOT_GREATER
} wait_condition_type_t;

typedef enum
{
    WAIT_TIMED_OUT,
    WAIT_CONDITION_HIT,
    WAIT_CANCELED
} wait_result_t;

typedef struct wait_condition
{
    wait_condition_type_t type;

    union
    {
        struct
        {
            dword_t *pointer;
            dword_t value;
        };

        struct wait_condition *conditions[VARIABLE_SIZE];
    };
} wait_condition_t;

typedef struct
{
    wait_condition_t *root;
    timeout_t timeout;
    qword_t timestamp;
    wait_result_t result;
} wait_t;

#ifndef PROCESS_TYPEDEF
#define PROCESS_TYPEDEF
typedef struct process process_t;
#endif

struct thread
{
    object_t header;
    list_entry_t in_queue_list;
    list_entry_t in_process_list;
    dword_t tid;
    priority_t priority;
    dword_t affinity;
    thread_state_t state;
    dword_t exit_code;
    dword_t quantum;
    qword_t running_ticks;
    process_t *owner_process; /* weak reference */
    dword_t terminated;
    int32_t frozen;

    void *kernel_stack;
    uintptr_t kernel_esp;

    int in_kernel;
    registers_t *last_context;
    bool_t terminating;
    processor_mode_t previous_mode;

    wait_t *wait;

    exception_handler_t kernel_handler;
    exception_info_t kernel_exception_info;
    exception_handler_t user_handler;
    exception_info_t user_exception_info;
};

#ifndef THREAD_TYPEDEF
#define THREAD_TYPEDEF
typedef struct thread thread_t;
#endif

extern bool_t scheduler_enabled;

thread_t *get_current_thread();
dword_t create_thread_internal(process_t *proc, thread_state_t *initial_state, dword_t flags, priority_t priority, void *kernel_stack, thread_t **new_thread);
dword_t terminate_thread_internal(thread_t *thread, dword_t return_value);
void scheduler(registers_t *regs);
wait_result_t scheduler_wait(wait_condition_t *condition, dword_t timeout);
dword_t create_system_thread(thread_procedure_t routine, dword_t flags, priority_t priority, dword_t stack_size, void *param, thread_t **new_thread);
void thread_lazy_fpu(void);
void thread_cleanup(object_t *thread);
dword_t thread_pre_wait(object_t *obj, void *parameter, wait_condition_t *condition);
void thread_init(void);

#endif
