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