1 /* 2 * z88dk z80 multi-task library 3 * 4 * $Id: preempt.h,v 1.8 2016-04-25 20:56:36 dom Exp $ 5 */ 6 7 8 #ifndef THREADING_PREEMPT_H 9 #define THREADING_PREEMPT_H 10 11 #include <sys/compiler.h> 12 13 14 #ifndef MAX_THREADS 15 #define MAX_THREADS 16 /* Make it a power of 2 - if this changes recompile library */ 16 #endif 17 18 19 /* Range of priorities */ 20 #define PRIORITY_MIN (-20) 21 #define PRIORITY_MAX 20 22 23 24 25 #define THREAD_SLEEP 1 /* Thread is sleeping */ 26 #define THREAD_SYSTEM 2 /* System thread, can't be killed */ 27 #define THREAD_USED 128 /* Thread slot is in use */ 28 29 30 typedef struct _thread thread_t; 31 32 struct _thread { 33 unsigned char pid; /**< Process id */ 34 unsigned char priority; /**< Priority of the thread */ 35 signed char nice; /**< Nice level */ 36 char flags; /**< Thread flags */ 37 char name[10]; /**< Name of the thread */ 38 void *sp; /**< Stack pointer for the thread */ 39 char extra[4]; /**< Extra storage for the scheduler */ 40 }; 41 42 43 #asm 44 DEFVARS 0 45 { 46 thread_pid ds.b 1 47 thread_priority ds.b 1 48 thread_nice ds.b 1 49 thread_flags ds.b 1 50 thread_name ds.b 10 51 thread_sp ds.w 1 52 thread_extra ds.b 4 53 THREAD_SIZE ds.b 1 54 } 55 #endasm 56 57 58 /* Schedulers can only be written in assembler due to parameters */ 59 typedef struct _scheduler scheduler_t; 60 61 struct _scheduler { 62 void (*schedule)(); /**< Routine that selects the next task */ 63 void (*task_init)(); /**< Initialise a task */ 64 void (*scheduler_init)(); /**< Initialise the entire scheduler */ 65 }; 66 67 /** \brief A threadbase_t lives in the user's code and holds control 68 * structures for the scheduler 69 */ 70 typedef struct _threadbase threadbase_t; 71 72 extern threadbase_t threadbase; 73 74 struct _threadbase { 75 thread_t *current; /**< Current thread */ 76 void (*generic_func)(); /**< Function called on every interrupt */ 77 void (*task_save_func)(); /**< For system specific task saving */ 78 void (*task_restore_func)(); /**< For system specific restoration */ 79 scheduler_t *scheduler; /**< For scheduling */ 80 int system_stack[25]; /**< Some storage for a system stack */ 81 void *temp_sp; /**< Temporary storage */ 82 int schedule_data[2]; /**< Any data for scheduling (opaque) */ 83 thread_t threads[MAX_THREADS]; /**< Allocated with extra memory here */ 84 }; 85 86 #asm 87 DEFVARS 0 { 88 current ds.w 1 89 generic_func ds.w 1 90 task_save_func ds.w 1 91 task_restore_func ds.w 1 92 scheduler ds.w 1 93 system_stack ds.w 25 94 temp_sp ds.w 1 95 schedule_data ds.w 2 96 threads ds.b 1 97 } 98 #endasm 99 100 101 /** \brief Initialise the task manager 102 * 103 * \param schedule - The scheduler to use 104 */ 105 #define thread_manager_init(schedule) thread_manager_init_real(schedule) 106 extern void __LIB__ thread_manager_init_real(scheduler_t *scheduler); 107 108 109 /** \brief Create a thread 110 * 111 * \param entry - The entry function 112 * \param stack - Address of the stack (will grow down) 113 * \param priority - Task priority 114 */ 115 extern thread_t __LIB__ *thread_create(void (*entry)(), void *stack, int priority) __smallc; 116 117 /** \brief Start the thread manager 118 * 119 * This function will start the thread manager and return control 120 * to the caller. 121 * 122 * The current code will continue to run at a priority of 1 123 */ 124 extern void __LIB__ thread_manager_start(); 125 126 /** \brief Thread manager that should be registered as the interrupt handler 127 * 128 * \note Do not call this function directly! 129 */ 130 extern void __LIB__ thread_manager(); 131 132 133 /** \brief The roundrobin scheduler 134 * 135 * \param ticks - Number of ticks per timeslice 136 * 137 * In the roundrobin model, each thread gets the same amount of time 138 */ 139 extern scheduler_t __LIB__ *roundrobin_scheduler(int ticks); 140 141 /** \brief The priority scheduler 142 * 143 * \param ticks - Number of ticks per timeslice 144 * 145 * In the priority model, we allocate each task a timeslice according 146 * to its priority and nice level 147 */ 148 extern scheduler_t __LIB__ *priority_scheduler(int ticks); 149 150 /** \brief Return the thread structure for the current thread 151 * 152 * \return The current thread 153 */ 154 #define thread_get_self() threadbase->current 155 156 /** \brief Return the id for the specified thread 157 * 158 * \param thr - The thread whose id should be retrieved 159 */ 160 #define thread_get_id(thr) thr->pid 161 162 /** \brief Set the priority of a thread 163 * 164 * \param thr - Thread 165 * \param prio - Priority 166 */ 167 #define thread_set_priority(thr, prio) thr->priority = prio 168 169 /** \brief Get the priority of a thread 170 * 171 * \param thr - Thread to query 172 * 173 * \return Priority 174 */ 175 #define thread_get_priority(th) thr->priority 176 177 /** \brief Mark a thread to sleep - i.e. don't run 178 * 179 * \param thr - Thread 180 */ 181 #define thread_sleep(thr) thr->flags |= THREAD_SLEEP; 182 183 /** \brief Wake a thread 184 * 185 * \param thr - Thread 186 */ 187 #define thread_wake(thr) thr->flags &= (~THREAD_SLEEP); 188 189 /** \brief Exit the current running thread 190 */ 191 extern void __LIB__ thread_exit(); 192 193 /** \brief Renice a given thread 194 * 195 * \param thread - Thread to renice 196 * \param nice - Adjustment to nice level 197 */ 198 extern void __LIB__ thread_renice(thread_t *thread, int nice); 199 200 201 #endif /* THREADING_PREEMPT_H */ 202