1 /*
2  * Copyright (C) 2020-2021 Alibaba Group Holding Limited
3  */
4 
5 #include <stdint.h>
6 #include <errno.h>
7 #include <time.h>
8 #include <pthread.h>
9 #include <sched.h>
10 #include <aos/kernel.h>
11 #include <aos/rhino.h>
12 
13 #include "internal/pthread.h"
14 #include "internal/sched.h"
15 
16 /* Note: pid is directly converted into pthread handle. */
_pid_to_pthread(pid_t pid)17 static inline pthread_t _pid_to_pthread(pid_t pid)
18 {
19     if (pid == -1) {
20         return NULL;
21     }
22 
23     /* todo, not surpport  */
24     return (pthread_t)(uintptr_t)pid;
25 }
26 
27 /* Convert pid to ptcb of the thread. */
sched_get_ptcb(pid_t pid)28 static inline pthread_tcb_t* sched_get_ptcb(pid_t pid)
29 {
30     pthread_t thread  = 0;
31 
32     thread = _pid_to_pthread(pid);
33     if (thread == 0) {
34         thread = pthread_self();
35     }
36 
37     return __pthread_get_tcb(thread);
38 }
39 
sched_yield(void)40 int sched_yield(void)
41 {
42     aos_task_yield();
43     return 0;
44 }
45 
sched_setscheduler(pid_t pid,int policy,const struct sched_param * param)46 int sched_setscheduler(pid_t pid, int policy, const struct sched_param *param)
47 {
48     int ret = 0;
49     pthread_tcb_t *ptcb = NULL;
50     uint8_t priority = 0;
51     int kpolicy = 0;
52     uint8_t old_policy = 0;
53 
54     ptcb = sched_get_ptcb(pid);
55     if (ptcb == NULL) {
56         errno = ESRCH;
57         return -1;
58     }
59 
60     kpolicy = sched_policy_posix2rhino(policy);
61     if (kpolicy == -1) {
62         errno = EINVAL;
63         return -1;
64     }
65 
66     if ((param == NULL) || (param->sched_priority < aos_sched_get_priority_min(kpolicy))
67         || (param->sched_priority > aos_sched_get_priority_max(kpolicy))) {
68         errno = EINVAL;
69         return -1;
70     }
71 
72     priority = sched_priority_posix2rhino(kpolicy, param->sched_priority);
73 
74     ret = aos_task_sched_policy_get(&(ptcb->task), &old_policy);
75     if (ret != 0) {
76         return -1;
77     }
78     old_policy = sched_policy_rhino2posix(old_policy);
79 
80     /* Change the policy and priority of the thread */
81     ret = aos_task_sched_policy_set(&(ptcb->task), kpolicy, priority);
82     if ((ret == 0) && (kpolicy == KSCHED_RR)) {
83         ret = aos_task_time_slice_set(&(ptcb->task), param->slice);
84     }
85     if (ret != 0) {
86         return -1;
87     }
88 
89     ptcb->attr.sched_priority = param->sched_priority;
90     ptcb->attr.sched_slice = param->slice;
91 
92     return old_policy;
93 }
94 
sched_getscheduler(pid_t pid)95 int sched_getscheduler(pid_t pid)
96 {
97     int ret = 0;
98     uint8_t policy = 0;
99     pthread_tcb_t *ptcb = NULL;
100 
101     ptcb = sched_get_ptcb(pid);
102     if (ptcb == NULL) {
103         errno = ESRCH;
104         return -1;
105     }
106 
107     ret = aos_task_sched_policy_get(&(ptcb->task), &policy);
108     if (ret != 0) {
109         errno = EINVAL;
110         return -1;
111     }
112 
113     return sched_policy_rhino2posix(policy);
114 }
115 
sched_setparam(pid_t pid,const struct sched_param * param)116 int sched_setparam(pid_t pid, const struct sched_param *param)
117 {
118     int ret = 0;
119     pthread_tcb_t *ptcb = NULL;
120     uint8_t old_priority = 0;
121     uint8_t priority = 0;
122     uint8_t kpolicy = 0;
123 
124     ptcb = sched_get_ptcb(pid);
125     if (ptcb == NULL) {
126         errno = ESRCH;
127         return -1;
128     }
129 
130     ret = aos_task_sched_policy_get(&(ptcb->task), &kpolicy);
131     if (ret != 0) {
132         return -1;
133     }
134 
135     if ((param == NULL) || (param->sched_priority < aos_sched_get_priority_min(kpolicy))
136         || (param->sched_priority > aos_sched_get_priority_max(kpolicy))) {
137         errno = EINVAL;
138         return -1;
139     }
140 
141     priority = sched_priority_posix2rhino(kpolicy, param->sched_priority);
142 
143     /* Change the priority of the thread. */
144     ret = aos_task_pri_change(&(ptcb->task), priority, &old_priority);
145     if (ret != 0) {
146         return -1;
147     }
148     ptcb->attr.sched_priority = param->sched_priority;
149 
150     if (kpolicy == KSCHED_RR) {
151         /* Change the time slice of the thread. */
152         ret = aos_task_time_slice_set(&(ptcb->task), param->slice);
153         if (ret != 0) {
154             return -1;
155         }
156         ptcb->attr.sched_slice = param->slice;
157     }
158 
159     return 0;
160 }
161 
sched_getparam(pid_t pid,struct sched_param * param)162 int sched_getparam(pid_t pid, struct sched_param *param)
163 {
164     int ret = 0;
165     pthread_tcb_t *ptcb = NULL;
166     int kpolicy = 0;
167 
168     if (param == NULL) {
169         errno = EINVAL;
170         return -1;
171     }
172 
173     ptcb = sched_get_ptcb(pid);
174     if (ptcb == NULL) {
175         errno = ESRCH;
176         return -1;
177     }
178 
179     ret = aos_task_pri_get(&(ptcb->task), (uint8_t *)&param->sched_priority);
180     if (ret != 0){
181         return -1;
182     }
183 
184     ret = aos_task_sched_policy_get(&(ptcb->task), (uint8_t *)&kpolicy);
185     if (ret != 0) {
186         return -1;
187     }
188     param->sched_priority = sched_priority_rhino2posix(kpolicy, param->sched_priority);
189 
190     /* Slice should be 0 if that is not RR policy. */
191     ret = aos_task_time_slice_get(&(ptcb->task), (uint32_t *)&param->slice);
192     if (ret != 0) {
193         return -1;
194     }
195 
196     return 0;
197 }
198 
sched_get_priority_max(int policy)199 int sched_get_priority_max(int policy)
200 {
201     int ret = 0;
202 
203     ret = sched_policy_posix2rhino(policy);
204     if (ret == -1) {
205         errno = EINVAL;
206         return -1;
207     }
208 
209     ret = aos_sched_get_priority_max(ret);
210     if (ret < 0) {
211         errno = -ret;
212         return -1;
213     }
214 
215     return ret;
216 }
217 
sched_get_priority_min(int policy)218 int sched_get_priority_min(int policy)
219 {
220     int ret = 0;
221 
222     ret = sched_policy_posix2rhino(policy);
223     if (ret == -1) {
224         errno = EINVAL;
225         return -1;
226     }
227 
228     ret = aos_sched_get_priority_min(ret);
229     if (ret < 0) {
230         errno = -ret;
231         return -1;
232     }
233 
234     return ret;
235 }
236 
sched_rr_get_interval(pid_t pid,struct timespec * interval)237 int sched_rr_get_interval(pid_t pid, struct timespec *interval)
238 {
239     int ret = 0;
240     pthread_tcb_t *ptcb = NULL;
241     uint8_t policy = 0;
242     uint32_t slice_ms = 0;
243 
244     if (interval == NULL) {
245         errno = EINVAL;
246         return -1;
247     }
248 
249     ptcb = sched_get_ptcb(pid);
250     if (ptcb == NULL) {
251         errno = ESRCH;
252         return -1;
253     }
254 
255     ret = aos_task_sched_policy_get(&(ptcb->task), &policy);
256     if ((ret != 0) || (policy != KSCHED_RR)) {
257         errno = EINVAL;
258         return -1;
259     }
260 
261     ret = aos_task_time_slice_get(&(ptcb->task), &slice_ms);
262     if (ret != 0) {
263         return -1;
264     }
265 
266     interval->tv_sec = slice_ms / 1000;
267     interval->tv_nsec = (slice_ms % 1000) * 1000000;
268 
269     return 0;
270 }
271