176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#ifndef _THREAD_H
276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define _THREAD_H
376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stddef.h>
576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <inttypes.h>
676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <limits.h>
776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stdbool.h>
876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <timer.h>
976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <sys/cpu.h>
1076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
1176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* The idle thread runs at this priority */
1276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define IDLE_THREAD_PRIORITY	INT_MAX
1376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
1476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* This priority should normally be used for hardware-polling threads */
1576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define POLL_THREAD_PRIORITY	(INT_MAX-1)
1676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
1776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct semaphore;
1876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
1976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct thread_list {
2076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    struct thread_list *next, *prev;
2176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman};
2276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
2376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
2476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Stack frame used by __switch_to, see thread_asm.S
2576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
2676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct thread_stack {
2776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int errno;
2876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    uint16_t rmsp, rmss;
2976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    uint32_t edi, esi, ebp, ebx;
3076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    void (*eip)(void);
3176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman};
3276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
3376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct thread_block {
3476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    struct thread_list list;
3576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    struct thread *thread;
3676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    struct semaphore *semaphore;
3776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    mstime_t block_time;
3876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    mstime_t timeout;
3976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    bool timed_out;
4076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman};
4176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
4276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define THREAD_MAGIC 0x3568eb7d
4376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
4476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct thread {
4576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    struct thread_stack *esp;	/* Must be first; stack pointer */
4676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    unsigned int thread_magic;
4776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    const char *name;		/* Name (for debugging) */
4876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    struct thread_list  list;
4976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    struct thread_block *blocked;
5076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    void *stack, *rmstack;	/* Stacks, iff allocated by malloc/lmalloc */
5176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    void *pvt; 			/* For the benefit of lwIP */
5276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int prio;
5376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman};
5476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
5576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanextern void (*sched_hook_func)(void);
5676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
5776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid __thread_process_timeouts(void);
5876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid __schedule(void);
5976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid __switch_to(struct thread *);
6076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid thread_yield(void);
6176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
6276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanextern struct thread *__current;
6376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline struct thread *current(void)
6476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
6576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return __current;
6676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
6776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
6876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct semaphore {
6976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int count;
7076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    struct thread_list list;
7176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman};
7276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
7376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define DECLARE_INIT_SEMAPHORE(sem, cnt)	\
7476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    struct semaphore sem = {			\
7576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	.count = (cnt),				\
7676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	.list =	{				\
7776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman            .next = &sem.list,			\
7876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman            .prev = &sem.list                   \
7976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        }					\
8076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
8176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
8276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanmstime_t sem_down(struct semaphore *, mstime_t);
8376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid sem_up(struct semaphore *);
8476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid sem_init(struct semaphore *, int);
8576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
8676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
8776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This marks a semaphore object as unusable; it will remain unusable
8876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * until sem_init() is called on it again.  This DOES NOT clear the
8976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * list of blocked processes on this semaphore!
9076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
9176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * It is also possible to mark the semaphore invalid by zeroing its
9276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * memory structure.
9376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
9476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline void sem_set_invalid(struct semaphore *sem)
9576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
9676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (!!sem)
9776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	sem->list.next = NULL;
9876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
9976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
10076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
10176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Ask if a semaphore object has been initialized.
10276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
10376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline bool sem_is_valid(struct semaphore *sem)
10476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
10576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return ((!!sem) && (!!sem->list.next));
10676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
10776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
10876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct thread *start_thread(const char *name, size_t stack_size, int prio,
10976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			    void (*start_func)(void *), void *func_arg);
11076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid __exit_thread(void);
11176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid kill_thread(struct thread *);
11276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
11376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid start_idle_thread(void);
11476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid test_thread(void);
11576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
11676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* _THREAD_H */
117