]> rtime.felk.cvut.cz Git - arc.git/blob - system/kernel/resource.c
More application changes
[arc.git] / system / kernel / resource.c
1 /* -------------------------------- Arctic Core ------------------------------\r
2  * Arctic Core - the open source AUTOSAR platform http://arccore.com\r
3  *\r
4  * Copyright (C) 2009  ArcCore AB <contact@arccore.com>\r
5  *\r
6  * This source code is free software; you can redistribute it and/or modify it\r
7  * under the terms of the GNU General Public License version 2 as published by the\r
8  * Free Software Foundation; See <http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt>.\r
9  *\r
10  * This program is distributed in the hope that it will be useful, but\r
11  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
12  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\r
13  * for more details.\r
14  * -------------------------------- Arctic Core ------------------------------*/\r
15 \r
16 #include "Os.h"\r
17 #include "application.h"\r
18 #include "internal.h"\r
19 #include "task_i.h"\r
20 #include "resource_i.h"\r
21 #include "sys.h"\r
22 #include <assert.h>\r
23 #include <string.h>\r
24 \r
25 \r
26 #if !defined(MAX)\r
27 #define MAX(_x,_y) (((_x) > (_y)) ? (_x) : (_y))\r
28 #endif\r
29 \r
30 \r
31 /*\r
32 Resource management at interrupt level is NOT supported\r
33 \r
34 \r
35 Testing\r
36 RM:\r
37 1. Priority ceiling: Call GetResource() from preemtive\r
38    task and activate a task with higher priority than the ceiling protocol.\r
39    The higher priority task should be swapped in.\r
40 2. Verify that you cannot allocate an internal resource with\r
41    a) GetResource()\r
42    b) ReleaseResource()\r
43 3. Internal resource. Allocate 1 internal resource to 3 tasks of different\r
44    priorities. Verify that\r
45    a) Higher priority tasks than the group can preement\r
46    b) For tasks which have the same or lower priority as the highest priority within a group,\r
47       the tasks within the group behave like non preemptable tasks ( OSEK 4.6.3)\r
48 4. Attempt to release a resource which has a lower ceiling priority\r
49    than the statically assigned priority of the calling task or\r
50    interrupt routine, E_OS_ACCESS\r
51 5. The  general  restriction  on  some  system  calls  that  they  are  not  to  be  called  with  resources\r
52   occupied (chapter 8.2) does not apply to internal resources, as internal resources are handled\r
53   within  those  calls.  However,  all  standard  resources  have  to  be  released  before  the  internal\r
54   resource can be released (see chapter 8.2, \93LIFO principle\94).\r
55 6. Check LIFO order. Return E_OS_ACCESS if not in LIFO order..\r
56 7. Test Os_IsrAddResource().\r
57 \r
58 \r
59 task\r
60 - GetResource(RES_SCHEDULER) will lock the scheduler even for ISR2\r
61 \r
62 TODO:\r
63 1. task.resourceAccess is already calculated by BSW builder. This is the bitmask\r
64    of what resources is accessable by the task.\r
65 2.\r
66 \r
67   task.rsrcAccessMask & (1 << RES_SCHEDULER)\r
68 \r
69  *\r
70  */\r
71 \r
72 /* INFO\r
73  * - If OsTaskSchedule = NON, Task it not preemptable, no internal resource may be assigned to a task\r
74  *                       (cause it already have one of prio 32)\r
75  *                       FULL, Task is preemptable\r
76  * - On Schedule() .... This service has no influence on tasks with no internal resource\r
77  *                      assigned (preemptable tasks).\r
78  *\r
79  * OSEK on internal resources:\r
80  * - Non preemptable tasks are a special group with an internal resource of the\r
81  *   same priority as RES_SCHEDULER assigned\r
82  *\r
83  *\r
84  * Assign RES_SCHEDULER with prio 32.\r
85  * Assign internal resources to NON preemptable task.\r
86  *\r
87  * So that leaves us with:\r
88  * - NON\r
89  *   - Cannot assign internal resource.\r
90  *     It automatically gets internal resource with same prio as RES_SCHEDULER\r
91  *\r
92  * - FULL\r
93  *   - Assigned. Used for grouping tasks.\r
94  *   - No assigned.\r
95  *\r
96  * What does that mean?\r
97  * - It's probably OK to do a GetResource(RES_SCHEDULER) from a NON task (although pointless)\r
98  * - GetResource(<any>) from a NON task is wrong\r
99  *\r
100  * Generation/Implementation:\r
101  * - Resources to 32. Alloc with .resourceAlloc = ((1<<RES_1) |(1<<RES_2));\r
102  * - Keep allocated resources as stack to comply with LIFO order.\r
103  * - A linked resource is just another name for an existing resource. See OsResource in Autosar SWS OS.\r
104  *   This means that no resource object should be generated, just the define in Os_Cfg.h\r
105  * - A task with Scheduling=NON have priority (although it's internal priority is 32)\r
106  *\r
107  */\r
108 \r
109 #define valid_standard_id() (rPtr->nr < OS_RESOURCE_CNT) //&& !(rPtr->type == RESOURCE_TYPE_INTERNAL) )\r
110 #define valid_internal_id() (rPtr->nr < OS_RESOURCE_CNT) //&& (rPtr->type == RESOURCE_TYPE_INTERNAL) )\r
111 \r
112 \r
113 \r
114 /**\r
115  * This call serves to enter critical sections in the code that are\r
116  * assigned to the resource referenced by <ResID>. A critical\r
117  * section shall always be left using ReleaseResource.\r
118  *\r
119  * The OSEK priority ceiling protocol for resource management is described\r
120  * in chapter 8.5. Nested resource occupation is only allowed if the inner\r
121  * critical sections are completely executed within the surrounding critical\r
122  * section (strictly stacked, see chapter 8.2, Restrictions when using\r
123  * resources). Nested occupation of one and the same resource is also\r
124  * forbidden! It is recommended that corresponding calls to GetResource and\r
125  * ReleaseResource appear within the same function.\r
126  *\r
127  * It is not allowed to use services which are points of rescheduling for\r
128  * non preemptable tasks  (TerminateTask,ChainTask,  Schedule  and  WaitEvent,\r
129  * see  chapter  4.6.2)  in critical  sections.\r
130  * Additionally,  critical  sections  are  to  be  left before completion of\r
131  * an interrupt service routine.\r
132  * Generally speaking, critical sections should be short.\r
133  * The service may be called from an ISR and from task level (see Figure 12-1).\r
134  *\r
135  * @param ResID\r
136  * @return\r
137  */\r
138 \r
139 \r
140 StatusType GetResource( ResourceType ResID ) {\r
141         StatusType rv = E_OK;\r
142         OsResourceType *rPtr;\r
143         uint32_t flags;\r
144 \r
145 #if     (OS_APPLICATION_CNT > 1)\r
146 \r
147         rv = Os_ApplHaveAccess( Os_ResourceGet(ResID)->accessingApplMask );\r
148         if( rv != E_OK ) {\r
149                 goto err;\r
150         }\r
151 \r
152 #endif\r
153 \r
154         Irq_Save(flags);\r
155 \r
156         if( Os_Sys.intNestCnt != 0 ) {\r
157 \r
158                 /* For interrupts to the scheduler resource seems just dumb to get */\r
159                 OsIsrVarType *isrPtr = Os_SysIsrGetCurr();\r
160 \r
161                 /* Check we can access it */\r
162                 if( ((isrPtr->constPtr->resourceMask & (1<< ResID)) == 0) ||\r
163                         ( ResID == RES_SCHEDULER )      ) {\r
164                         rv = E_OS_ID;\r
165                         goto err;\r
166                 }\r
167 \r
168                 rPtr = Os_ResourceGet(ResID);\r
169 \r
170                 /* ceiling prio for ISR seems strange...so no */\r
171                 if( rPtr->owner != NO_TASK_OWNER ) {\r
172                         rv = E_OS_ACCESS;\r
173                         Irq_Restore(flags);\r
174                         goto err;\r
175                 }\r
176                 /* Add the resource to the list of resources held by this isr */\r
177                 Os_IsrResourceAdd(rPtr,isrPtr);\r
178 \r
179         } else {\r
180                 OsTaskVarType *taskPtr = Os_SysTaskGetCurr();\r
181 \r
182                 if( ResID == RES_SCHEDULER ) {\r
183                         rPtr = &Os_Sys.resScheduler;\r
184                 } else {\r
185                         /* Check we can access it */\r
186                         if( (taskPtr->constPtr->resourceAccess & (1<< ResID)) == 0 ) {\r
187                                 rv = E_OS_ID;\r
188                                 goto err;\r
189                         }\r
190 \r
191                         rPtr = Os_ResourceGet(ResID);\r
192                 }\r
193 \r
194                 /* Check for invalid configuration */\r
195                 if( (rPtr->owner != NO_TASK_OWNER) ||\r
196                         (taskPtr->activePriority > rPtr->ceiling_priority) )\r
197                 {\r
198                         rv = E_OS_ACCESS;\r
199                         Irq_Restore(flags);\r
200                         goto err;\r
201                 }\r
202                 /* Add the resource to the list of resources held by this task */\r
203                 Os_TaskResourceAdd(rPtr,taskPtr);\r
204         }\r
205 \r
206         Irq_Restore(flags);\r
207 \r
208         if (rv != E_OK)\r
209                 goto err;\r
210 \r
211         OS_STD_END_1(OSServiceId_GetResource,ResID);\r
212 }\r
213 \r
214 /**\r
215  * ReleaseResource   is   the   counterpart   of   GetResource   and\r
216  * serves to leave critical sections in the code that are assigned to\r
217  * the resource referenced by <ResID>.\r
218  *\r
219  * For  information  on  nesting  conditions,  see  particularities  of\r
220  * GetResource. The service may be called from an ISR and from task level (see\r
221  * Figure 12-1).\r
222  *\r
223  * @param ResID\r
224  * @return\r
225  */\r
226 \r
227 StatusType ReleaseResource( ResourceType ResID) {\r
228         StatusType rv = E_OK;\r
229         OsTaskVarType *pcbPtr = Os_SysTaskGetCurr();\r
230         OsResourceType *rPtr;\r
231         uint32_t flags;\r
232 \r
233         Irq_Save(flags);\r
234         if( ResID == RES_SCHEDULER ) {\r
235                 rPtr = &Os_Sys.resScheduler;\r
236         } else {\r
237                 /* Check we can access it */\r
238                 if( (pcbPtr->constPtr->resourceAccess & (1<< ResID)) == 0 ) {\r
239                         rv = E_OS_ID;\r
240                         goto err;\r
241                 }\r
242                 rPtr = Os_ResourceGet(ResID);\r
243         }\r
244 \r
245         /* Check for invalid configuration */\r
246         if( rPtr->owner == NO_TASK_OWNER)\r
247         {\r
248                 rv = E_OS_NOFUNC;\r
249                 Irq_Restore(flags);\r
250                 goto err;\r
251         }\r
252 \r
253         if( (pcbPtr->activePriority < rPtr->ceiling_priority))\r
254         {\r
255                 rv = E_OS_ACCESS;\r
256                 Irq_Restore(flags);\r
257                 goto err;\r
258         }\r
259 \r
260         Os_TaskResourceRemove(rPtr,pcbPtr);\r
261 \r
262         /* do a rescheduling (in some cases) (see OSEK OS 4.6.1) */\r
263         if ( (pcbPtr->constPtr->scheduling == FULL) &&\r
264                  (Os_Sys.intNestCnt == 0) &&\r
265                  (Os_SchedulerResourceIsFree()) ) {\r
266 \r
267                 OsTaskVarType* top_pcb = Os_TaskGetTop();\r
268 \r
269                 /* only dispatch if some other ready task has higher prio */\r
270                 if (top_pcb->activePriority > Os_SysTaskGetCurr()->activePriority) {\r
271                         Os_Dispatch(OP_RELEASE_RESOURCE);\r
272                 }\r
273         }\r
274         Irq_Restore(flags);\r
275 \r
276         OS_STD_END_1(OSServiceId_ReleaseResource,ResID);\r
277 }\r
278 \r
279 \r
280 void Os_ResourceGetInternal( void ) {\r
281         OsTaskVarType *pcbPtr = Os_SysTaskGetCurr();\r
282         OsResourceType *rt = pcbPtr->constPtr->resourceIntPtr;\r
283 \r
284         if( rt != NULL ) {\r
285                 OS_DEBUG(D_RESOURCE,"Get IR proc:%s prio:%u old_task_prio:%u\n",\r
286                                 Os_SysTaskGetCurr()->name,\r
287                                 (unsigned)rt->ceiling_priority,\r
288                                 (unsigned)rt->old_task_prio);\r
289                 Os_TaskResourceAdd(rt,pcbPtr);\r
290         }\r
291 }\r
292 \r
293 void Os_ResourceReleaseInternal( void ) {\r
294         OsTaskVarType *pcbPtr = Os_SysTaskGetCurr();\r
295         OsResourceType *rt = pcbPtr->constPtr->resourceIntPtr;\r
296 \r
297         if(  rt != NULL ) {\r
298                 OS_DEBUG(D_RESOURCE,"Rel IR proc:%s prio:%u old_task_prio:%u\n",\r
299                                 Os_SysTaskGetCurr()->name,\r
300                                 (unsigned)rt->ceiling_priority,\r
301                                 (unsigned)rt->old_task_prio);\r
302                 Os_TaskResourceRemove(rt,pcbPtr);\r
303         }\r
304 }\r
305 \r
306 \r
307 \r
308 /**\r
309  *\r
310  * @param pcb_p\r
311  * @return\r
312  */\r
313 void Os_ResourceInit( void ) {\r
314         //TAILQ_INIT(&pcb_p->resourceHead);\r
315         OsTaskVarType *pcb_p;\r
316         OsResourceType *rsrc_p;\r
317         int topPrio;\r
318 \r
319 \r
320         /* For now, assign the scheduler resource here */\r
321         Os_Sys.resScheduler.ceiling_priority = OS_RES_SCHEDULER_PRIO;\r
322         strcpy(Os_Sys.resScheduler.id,"RES_SCHEDULER");\r
323         Os_Sys.resScheduler.nr = RES_SCHEDULER;\r
324         Os_Sys.resScheduler.owner = NO_TASK_OWNER;\r
325 \r
326         /* Calculate ceiling priority\r
327          * We make this as simple as possible. The ceiling priority\r
328          * is set to the same priority as the highest priority task that\r
329          * access it.\r
330          *\r
331          * Note that this applies both internal and standard resources.\r
332          * */\r
333         for( int i=0; i < OS_RESOURCE_CNT; i++) {\r
334                 rsrc_p = Os_ResourceGet(i);\r
335                 topPrio = 0;\r
336 \r
337                 for( int pi = 0; pi < OS_TASK_CNT; pi++) {\r
338 \r
339                         pcb_p = Os_TaskGet(pi);\r
340 \r
341 \r
342                         if(pcb_p->constPtr->resourceAccess & (1<<i) ) {\r
343                                 topPrio = MAX(topPrio,pcb_p->constPtr->prio);\r
344                         }\r
345 \r
346                         /* Generator fix, add RES_SCHEDULER */\r
347 //                      pcb_p->constPtr->resourceAccess |= (1 << RES_SCHEDULER) ;\r
348                 }\r
349                 rsrc_p->ceiling_priority = topPrio;\r
350         }\r
351 }\r
352 \r