1 /*
2  * Copyright (C) 2015-2017 Alibaba Group Holding Limited
3  */
4 
5 #ifndef K_TASK_H
6 #define K_TASK_H
7 
8 #ifdef __cplusplus
9 extern "C" {
10 #endif
11 
12 /** @addtogroup aos_rhino task
13  *  Task management
14  *
15  *  @{
16  */
17 
18 
19 /**
20  * Task status
21  */
22 typedef enum {
23     K_SEED,
24     K_RDY,              /**< READY, task in ready list (g_ready_queue) */
25     K_PEND,             /**< PEND, task in tick list (g_tick_head) and block list (sem/mutex/queue/...) */
26     K_SUSPENDED,
27     K_PEND_SUSPENDED,
28     K_SLEEP,            /**< SLEEP, task tick list (g_tick_head) */
29     K_SLEEP_SUSPENDED,
30     K_DELETED,
31 } task_stat_t;
32 
33 typedef void (*task_entry_t)(void *arg);
34 
35 /**
36  * Task control information
37  */
38 typedef struct {
39     /**<
40      *  Task SP, update when task switching.
41      *  Access by assemble code, so do not change position.
42      */
43     void            *task_stack;
44     /**< access by activation, so do not change position */
45     const name_t    *task_name;
46 #if (RHINO_CONFIG_TASK_INFO > 0)
47     /**< access by assemble code, so do not change position */
48     void            *user_info[RHINO_CONFIG_TASK_INFO_NUM];
49 #endif
50 
51 #if (RHINO_CONFIG_USER_SPACE > 0)
52     void            *task_ustack;
53     uint32_t         ustack_size;
54     uint32_t         pid;
55     uint8_t          mode;
56     uint8_t          is_proc;
57     cpu_stack_t     *task_ustack_base;
58     klist_t          task_user;
59     void            *task_group;
60 #endif
61     /**<
62      *  Task stack info
63      *  start 'task_stack_base', len 'stack_size * sizeof(cpu_stack_t)'
64      */
65     cpu_stack_t     *task_stack_base;
66     size_t           stack_size;
67     /**<
68      *  Put task into different linked lists according to the status:
69      *  1. ready queue. The list hade is g_ready_queue->cur_list_item[prio]
70      *  2. The pending queue. The list hade is blk_obj in the blocking object (sem / mutex / queue, etc.).
71      *     The final blocking result is recorded in blk_state
72      */
73     klist_t          task_list;
74     /**< Count of entering the K_SUSPENDED state */
75     suspend_nested_t suspend_count;
76     /**< Mutex owned by this task */
77     struct mutex_s  *mutex_list;
78 #if (RHINO_CONFIG_KOBJ_LIST > 0)
79     /**< Link all task for statistics */
80     klist_t          task_stats_item;
81 #endif
82     /**< Put task into the timeout list of the tick, list head is 'g_tick_head' */
83     klist_t          tick_list;
84     /**< When 'g_tick_count' reaches tick_match, task's PEND or SLEEP state expires. */
85     tick_t           tick_match;
86     /**< Countdown of the PEND state */
87     tick_t           tick_remain;
88 
89     /**< Passing massage, for 'queue' and 'buf_queue' */
90     void            *msg;
91 #if (RHINO_CONFIG_BUF_QUEUE > 0)
92     /**< Record the msg length, for 'buf_queue'. */
93     size_t           bq_msg_size;
94 #endif
95     /**<  */
96     /**< Task status */
97     task_stat_t      task_state;
98     /**< Reasons for the end of the blocking state */
99     blk_state_t      blk_state;
100 
101     /* Task block on mutex, queue, semphore, event */
102     blk_obj_t       *blk_obj;
103 
104     uint32_t         task_id;
105 #if (RHINO_CONFIG_MM_DEBUG > 0)
106     uint32_t         task_alloc_size;
107 #endif
108 
109 #if (RHINO_CONFIG_TASK_SEM > 0)
110     /**< Task semaphore  */
111     struct sem_s    *task_sem_obj;
112 #endif
113 
114 #if (RHINO_CONFIG_SYS_STATS > 0)
115     size_t           task_free_stack_size;
116     ctx_switch_t     task_ctx_switch_times;
117     uint64_t         task_time_total_run;
118     uint64_t         task_time_total_run_prev;
119     lr_timer_t       task_time_this_run;
120     lr_timer_t       task_exec_time;
121     lr_timer_t       task_time_start;
122     hr_timer_t       task_intrpt_disable_time_max;
123     hr_timer_t       task_sched_disable_time_max;
124 #endif
125 
126 #if (RHINO_CONFIG_SCHED_RR > 0)
127     /**< During this round of scheduling, tasks can execute 'time_slice' ticks */
128     uint32_t         time_slice;
129     /**< Once RR scheduling, tasks can execute a total of 'time_total' ticks */
130     uint32_t         time_total;
131 #endif
132 
133 #if (RHINO_CONFIG_EVENT_FLAG > 0)
134     uint32_t         pend_flags;
135     void            *pend_info;
136     uint8_t          pend_option;
137 #endif
138     /**< KSCHED_FIFO / KSCHED_RR / KSCHED_CFS */
139     uint8_t          sched_policy;
140 
141 #if (RHINO_CONFIG_SCHED_CFS > 0)
142     cfs_node         node;
143 #endif
144     /**< On which CPU the task runs */
145     uint8_t          cpu_num;
146 
147 #if (RHINO_CONFIG_CPU_NUM > 1)
148     /**< Whether the task is binded to the cpu, 0 no, 1 yes */
149     uint8_t          cpu_binded;
150     /**< Whether the task is ready to execute, 0 no, 1 yes */
151     uint8_t          cur_exc;
152     klist_t          task_del_item;
153 #endif
154 
155 #if (RHINO_CONFIG_TASK_DEL > 0)
156     uint8_t          cancel;
157 #endif
158 
159     /**< current prio */
160     uint8_t          prio;
161     /**< base prio */
162     uint8_t          b_prio;
163     /**< buffer from internal malloc or caller input */
164     uint8_t          mm_alloc_flag;
165 
166     void            *ptcb;  /* pthread control block */
167 
168 #if (RHINO_CONFIG_NEWLIBC_REENT > 0)
169     struct _reent *newlibc_reent; /* newlib libc reentrancy */
170 #endif
171 } ktask_t;
172 
173 /**
174  * Create a task and provide the stack space.
175  *
176  * @param[in]  task       the task to be created (the space is provided outside, by user)
177  * @param[in]  name       the name of task, which shall be unique
178  * @param[in]  arg        the parameter of task enter function
179  * @param[in]  pri        the priority of task
180  * @param[in]  ticks      the time slice
181  * @param[in]  stack_buf  the start address of task stack
182  * @param[in]  stack_size task stack size = stack_size * sizeof(cpu_stack_t)
183  * @param[in]  entry      the entry function of task
184  * @param[in]  autorun    the autorunning flag of task
185  *
186  * @return  the operation status, RHINO_SUCCESS is OK, others is error
187  */
188 kstat_t krhino_task_create(ktask_t *task, const name_t *name, void *arg,
189                            uint8_t prio, tick_t ticks, cpu_stack_t *stack_buf,
190                            size_t stack_size, task_entry_t entry, uint8_t autorun);
191 
192 kstat_t krhino_cfs_task_create(ktask_t *task, const name_t *name, void *arg,
193                                uint8_t prio, cpu_stack_t *stack_buf, size_t stack_size,
194                                task_entry_t entry, uint8_t autorun);
195 
196 #if (RHINO_CONFIG_CPU_NUM > 1)
197 /**
198  * Create a task and provide the stack space, bind the task to specific cpu.
199  *
200  * @param[in]  task       the task to be created (the space is provided outside, by user)
201  * @param[in]  name       the name of task, which shall be unique
202  * @param[in]  arg        the parameter of task enter function
203  * @param[in]  pri        the priority of task
204  * @param[in]  ticks      the time slice
205  * @param[in]  stack_buf  the start address of task stack
206  * @param[in]  stack_size task stack size = stack_size * sizeof(cpu_stack_t)
207  * @param[in]  entry      the entry function of task
208  * @param[in]  cpu_num    the cpu that task bind to
209  * @param[in]  autorun    the autorunning flag of task
210  *
211  * @return  the operation status, RHINO_SUCCESS is OK, others is error
212  */
213 kstat_t krhino_task_cpu_create(ktask_t *task, const name_t *name, void *arg,
214                                uint8_t prio, tick_t ticks, cpu_stack_t *stack_buf,
215                                size_t stack_size, task_entry_t entry, uint8_t cpu_num,
216                                uint8_t autorun);
217 
218 kstat_t krhino_cfs_task_cpu_create(ktask_t *task, const name_t *name, void *arg,
219                                    uint8_t prio, cpu_stack_t *stack_buf, size_t stack_size,
220                                    task_entry_t entry, uint8_t cpu_num, uint8_t autorun);
221 
222 /**
223  * Bind a task to specific cpu.
224  *
225  * @param[in]  task       the task to be binded
226  * @param[in]  cpu_num    the cpu that task bind to
227  *
228  * @return  the operation status, RHINO_SUCCESS is OK, others is error
229  */
230 kstat_t krhino_task_cpu_bind(ktask_t *task, uint8_t cpu_num);
231 
232 /**
233  * Unbind a task.
234  *
235  * @param[in]  task       the task to be binded
236  *
237  * @return  the operation status, RHINO_SUCCESS is OK, others is error
238  */
239  kstat_t krhino_task_cpu_unbind(ktask_t *task);
240 #endif
241 
242 
243 #if (RHINO_CONFIG_KOBJ_DYN_ALLOC > 0)
244 /**
245  * Create a task and malloc the stack space.
246  *
247  * @param[out] task     the task to be created (the space is provided inside, from heap)
248  * @param[in]  name     the name of task
249  * @param[in]  arg      the parameter of task enter function
250  * @param[in]  pri      the priority of task
251  * @param[in]  ticks    the time slice
252  * @param[in]  stack    task stack size = stack * sizeof(cpu_stack_t)
253  * @param[in]  entry    the entry function of task
254  * @param[in]  autorun  the autorunning flag of task
255  *
256  * @return  the operation status, RHINO_SUCCESS is OK, others is error
257  */
258 kstat_t krhino_task_dyn_create(ktask_t **task, const name_t *name, void *arg,
259                                uint8_t pri, tick_t ticks, size_t stack,
260                                task_entry_t entry, uint8_t autorun);
261 
262 kstat_t krhino_cfs_task_dyn_create(ktask_t **task, const name_t *name, void *arg,
263                                    uint8_t pri, size_t stack, task_entry_t entry,
264                                    uint8_t autorun);
265 
266 #if (RHINO_CONFIG_CPU_NUM > 1)
267 /**
268  * Create a task and malloc the stack space, bind the task to specific cpu.
269  *
270  * @param[in]  task       the task to be created (the space is provided inside, from heap)
271  * @param[in]  name       the name of task, which shall be unique
272  * @param[in]  arg        the parameter of task enter function
273  * @param[in]  pri        the priority of task
274  * @param[in]  ticks      the time slice
275  * @param[in]  stack      task stack size = stack * sizeof(cpu_stack_t)
276  * @param[in]  entry      the entry function of task
277  * @param[in]  cpu_num    the cpu that task bind to
278  * @param[in]  autorun    the autorunning flag of task
279  *
280  * @return  the operation status, RHINO_SUCCESS is OK, others is error
281  */
282 kstat_t krhino_task_cpu_dyn_create(ktask_t **task, const name_t *name, void *arg,
283                                    uint8_t pri, tick_t ticks, size_t stack,
284                                    task_entry_t entry, uint8_t cpu_num, uint8_t autorun);
285 
286 kstat_t krhino_cfs_task_cpu_dyn_create(ktask_t **task, const name_t *name, void *arg,
287                                        uint8_t pri, size_t stack, task_entry_t entry,
288                                        uint8_t cpu_num, uint8_t autorun);
289 #endif
290 #endif
291 
292 #if (RHINO_CONFIG_TASK_DEL > 0)
293 /**
294  * Delete a task, free the task stack.
295  *
296  * @param[in]  task  the task to be deleted.
297  *
298  * @return  the operation status, RHINO_SUCCESS is OK, others is error
299  */
300 kstat_t krhino_task_del(ktask_t *task);
301 #if (RHINO_CONFIG_KOBJ_DYN_ALLOC > 0)
302 /**
303  * Delete a task, free the task stack, free ktask_t.
304  *
305  * @param[in]  task  the task to be deleted.
306  *
307  * @return  the operation status, RHINO_SUCCESS is OK, others is error
308  */
309 kstat_t krhino_task_dyn_del(ktask_t *task);
310 #endif
311 
312 /**
313  * Cancel a task.
314  *
315  * @param[in]  task  the task to be killed.
316  *
317  * @return  the operation status, RHINO_SUCCESS is OK, others is error
318  */
319 kstat_t krhino_task_cancel(ktask_t *task);
320 
321 /**
322  * Check the task self whether is canceled or not.
323  *
324  * @param[in]  NULL
325  *
326  * @return  false or true
327  */
328 RHINO_BOOL krhino_task_cancel_chk(void);
329 #endif
330 
331 /**
332  * Task sleep for some ticks.
333  *
334  * @param[in]  ticks  the ticks to sleep
335  *
336  * @return  the operation status, RHINO_SUCCESS is OK, others is error
337  */
338 kstat_t krhino_task_sleep(tick_t ticks);
339 
340 /**
341  * Yield a task.
342  *
343  * @param[in]  NULL
344  *
345  * @return the operation status, RHINO_SUCCESS is OK, others is error
346  */
347 kstat_t krhino_task_yield(void);
348 
349 /**
350  * Get the current task for this cpu.
351  *
352  * @param[in]  NULL
353  *
354  * @return the current task
355  */
356 ktask_t *krhino_cur_task_get(void);
357 
358 /**
359  * Suspend a task.
360  *
361  * @param[in]  task  the task to be suspended
362  *
363  * @return  the operation status, RHINO_SUCCESS is OK, others is error
364  */
365 kstat_t krhino_task_suspend(ktask_t *task);
366 
367 /**
368  * Resume a task from SUSPEND.
369  *
370  * @param[in]  task  the task to be resumed
371  *
372  * @return the operation status, RHINO_SUCCESS is OK, others is error
373  */
374 kstat_t krhino_task_resume(ktask_t *task);
375 
376 /**
377  * Get min free stack size in the total runtime.
378  *
379  * @param[in]  task  the task where get free stack size.
380  * @param[out] free  the free task stack size
381  *
382  * @return  the operation status, RHINO_SUCCESS is OK, others is error
383  */
384 kstat_t krhino_task_stack_min_free(ktask_t *task, size_t *free);
385 
386 /**
387  * Change the priority of task.
388  *
389  * @param[in]   task     the task to be changed priority
390  * @param[in]   pri      the priority to be changed.
391  * @param[out]  old_pri  the old priority
392  *
393  * @return  the operation status, RHINO_SUCCESS is OK, others is error
394  */
395 kstat_t krhino_task_pri_change(ktask_t *task, uint8_t pri, uint8_t *old_pri);
396 
397 /**
398  * Wakup the task, SUSPENDED/SLEEP/PEND -> READY.
399  *
400  * @param[in]  task  the task to be Wakup
401  *
402  * @return  the operation status, RHINO_SUCCESS is OK, others is error
403  */
404 kstat_t krhino_task_wait_abort(ktask_t *task);
405 
406 #if (RHINO_CONFIG_SCHED_RR > 0)
407 /**
408  * Set task timeslice when KSCHED_RR.
409  *
410  * @param[in]  task   the task to be set timeslice
411  * @param[in]  slice  the task time slice
412  *
413  * @return  the operation status, RHINO_SUCCESS is OK, others is error
414  */
415 kstat_t krhino_task_time_slice_set(ktask_t *task, size_t slice);
416 
417 /**
418  * Set task sched policy.
419  *
420  * @param[in]  task    the task to be set
421  * @param[in]  policy  KSCHED_FIFO / KSCHED_RR / KSCHED_CFS
422  *
423  * @return  the operation status, RHINO_SUCCESS is OK, others is error
424  */
425 kstat_t krhino_sched_policy_set(ktask_t *task, uint8_t policy);
426 
427 
428 /**
429  * Set task sched policy and priority.
430  *
431  * @param[in]  task    the task to be set timeslice
432  * @param[in]  policy  KSCHED_FIFO / KSCHED_RR / KSCHED_CFS
433  * @param[in]  pri     the prio of task
434  *
435  * @return  the operation status, RHINO_SUCCESS is OK, others is error
436  */
437 kstat_t krhino_sched_param_set(ktask_t *task, uint8_t policy, uint8_t pri);
438 
439 /**
440  * Get task sched policy.
441  *
442  * @param[in]   task    the task to be get timeslice
443  * @param[out]  policy  KSCHED_FIFO / KSCHED_RR / KSCHED_CFS
444  *
445  * @return  the operation status, RHINO_SUCCESS is OK, others is error
446  */
447 kstat_t krhino_sched_policy_get(ktask_t *task, uint8_t *policy);
448 #endif
449 
450 #if (RHINO_CONFIG_TASK_INFO > 0)
451 /**
452  * Set task private infomation.
453  *
454  * @param[in]   task  the task to be set private infomation
455  * @param[in]   idx   set the info[idx], < RHINO_CONFIG_TASK_INFO_NUM
456  * @param[in]   info  the private information
457  *
458  * @return  the operation status, RHINO_SUCCESS is OK, others is error
459  */
460 kstat_t krhino_task_info_set(ktask_t *task, size_t idx, void *info);
461 
462 /**
463  * Get task private infomation.
464  *
465  * @param[in]   task  the task to be get private infomation
466  * @param[in]   idx   get the info[idx], < RHINO_CONFIG_TASK_INFO_NUM
467  * @param[out]  info  to save private infomation
468  *
469  * @return  the task private information
470  */
471 kstat_t krhino_task_info_get(ktask_t *task, size_t idx, void **info);
472 #endif
473 
474 /**
475  * Task self delete, run when task ends.
476  *
477  * @param[in]   NULL
478  *
479  * @return  NULL
480  */
481 void krhino_task_deathbed(void);
482 
483 /**
484  * Get the task by name.
485  *
486  * @param[in]   name    task name
487  *
488  * @return  the task
489  */
490 ktask_t *krhino_task_find(name_t *name);
491 
492 /** @} */
493 
494 #ifdef __cplusplus
495 }
496 #endif
497 
498 #endif /* K_TASK_H */
499 
500