1 /* -------------------------------- Arctic Core ------------------------------
\r
2 * Arctic Core - the open source AUTOSAR platform http://arccore.com
\r
4 * Copyright (C) 2009 ArcCore AB <contact@arccore.com>
\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
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
14 * -------------------------------- Arctic Core ------------------------------*/
\r
17 #include "internal.h"
\r
23 #define MAX(_x,_y) (((_x) > (_y)) ? (_x) : (_y))
\r
28 Resource management at interrupt level is NOT supported
\r
33 1. Priority ceiling: Call GetResource() from preemtive
\r
34 task and activate a task with higher priority than the ceiling protocol.
\r
35 The higher priority task should be swapped in.
\r
36 2. Verify that you cannot allocate an internal resource with
\r
38 b) ReleaseResource()
\r
39 3. Internal resource. Allocate 1 internal resource to 3 tasks of different
\r
40 priorities. Verify that
\r
41 a) Higher priority tasks than the group can preement
\r
42 b) For tasks which have the same or lower priority as the highest priority within a group,
\r
43 the tasks within the group behave like non preemptable tasks ( OSEK 4.6.3)
\r
44 4. Attempt to release a resource which has a lower ceiling priority
\r
45 than the statically assigned priority of the calling task or
\r
46 interrupt routine, E_OS_ACCESS
\r
47 5. The general restriction on some system calls that they are not to be called with resources
\r
48 occupied (chapter 8.2) does not apply to internal resources, as internal resources are handled
\r
49 within those calls. However, all standard resources have to be released before the internal
\r
50 resource can be released (see chapter 8.2,
\93LIFO principle
\94).
\r
51 6. Check LIFO order. Return E_OS_ACCESS if not in LIFO order..
\r
52 7. Test Os_IsrAddResource().
\r
56 - GetResource(RES_SCHEDULER) will lock the scheduler even for ISR2
\r
59 1. task.resourceAccess is already calculated by BSW builder. This is the bitmask
\r
60 of what resources is accessable by the task.
\r
63 task.rsrcAccessMask & (1 << RES_SCHEDULER)
\r
69 * - If OsTaskSchedule = NON, Task it not preemptable, no internal resource may be assigned to a task
\r
70 * (cause it already have one of prio 32)
\r
71 * FULL, Task is preemptable
\r
72 * - On Schedule() .... This service has no influence on tasks with no internal resource
\r
73 * assigned (preemptable tasks).
\r
75 * OSEK on internal resources:
\r
76 * - Non preemptable tasks are a special group with an internal resource of the
\r
77 * same priority as RES_SCHEDULER assigned
\r
80 * Assign RES_SCHEDULER with prio 32.
\r
81 * Assign internal resources to NON preemptable task.
\r
83 * So that leaves us with:
\r
85 * - Cannot assign internal resource.
\r
86 * It automatically gets internal resource with same prio as RES_SCHEDULER
\r
89 * - Assigned. Used for grouping tasks.
\r
92 * What does that mean?
\r
93 * - It's probably OK to do a GetResource(RES_SCHEDULER) from a NON task (although pointless)
\r
94 * - GetResource(<any>) from a NON task is wrong
\r
96 * Generation/Implementation:
\r
97 * - Resources to 32. Alloc with .resourceAlloc = ((1<<RES_1) |(1<<RES_2));
\r
98 * - Keep allocated resources as stack to comply with LIFO order.
\r
99 * - A linked resource is just another name for an existing resource. See OsResource in Autosar SWS OS.
\r
100 * This means that no resource object should be generated, just the define in Os_Cfg.h
\r
101 * - A task with Scheduling=NON have priority (although it's internal priority is 32)
\r
105 #define valid_standard_id() (rPtr->nr < OS_RESOURCE_CNT) //&& !(rPtr->type == RESOURCE_TYPE_INTERNAL) )
\r
106 #define valid_internal_id() (rPtr->nr < OS_RESOURCE_CNT) //&& (rPtr->type == RESOURCE_TYPE_INTERNAL) )
\r
109 void Os_ResourceAlloc( OsResourceType *rPtr, OsPcbType *pcbPtr) {
\r
110 /* Save old task prio in resource and set new task prio */
\r
111 rPtr->owner = pcbPtr->pid;
\r
112 rPtr->old_task_prio = pcbPtr->prio;
\r
113 pcbPtr->prio = rPtr->ceiling_priority;
\r
115 if( rPtr->type != RESOURCE_TYPE_INTERNAL ) {
\r
116 TAILQ_INSERT_TAIL(&pcbPtr->resource_head, rPtr, listEntry);
\r
120 void Os_ResourceFree( OsResourceType *rPtr , OsPcbType *pcbPtr) {
\r
121 assert( rPtr->owner == pcbPtr->pid );
\r
122 rPtr->owner = NO_TASK_OWNER;
\r
123 pcbPtr->prio = rPtr->old_task_prio;
\r
125 if( rPtr->type != RESOURCE_TYPE_INTERNAL ) {
\r
126 /* The list can't be empty here */
\r
127 assert( !TAILQ_EMPTY(&pcbPtr->resource_head) );
\r
129 /* The list should be popped in LIFO order */
\r
130 assert( TAILQ_LAST(&pcbPtr->resource_head, head) == rPtr );
\r
132 /* Remove the entry */
\r
133 TAILQ_REMOVE(&pcbPtr->resource_head, rPtr, listEntry);
\r
138 * This call serves to enter critical sections in the code that are
\r
139 * assigned to the resource referenced by <ResID>. A critical
\r
140 * section shall always be left using ReleaseResource.
\r
142 * The OSEK priority ceiling protocol for resource management is described
\r
143 * in chapter 8.5. Nested resource occupation is only allowed if the inner
\r
144 * critical sections are completely executed within the surrounding critical
\r
145 * section (strictly stacked, see chapter 8.2, Restrictions when using
\r
146 * resources). Nested occupation of one and the same resource is also
\r
147 * forbidden! It is recommended that corresponding calls to GetResource and
\r
148 * ReleaseResource appear within the same function.
\r
150 * It is not allowed to use services which are points of rescheduling for
\r
151 * non preemptable tasks (TerminateTask,ChainTask, Schedule and WaitEvent,
\r
152 * see chapter 4.6.2) in critical sections.
\r
153 * Additionally, critical sections are to be left before completion of
\r
154 * an interrupt service routine.
\r
155 * Generally speaking, critical sections should be short.
\r
156 * The service may be called from an ISR and from task level (see Figure 12-1).
\r
163 StatusType GetResource( ResourceType ResID ) {
\r
164 StatusType rv = E_OK;
\r
165 OsPcbType *pcbPtr = Os_TaskGetCurrent();
\r
166 OsResourceType *rPtr;
\r
171 if( ResID == RES_SCHEDULER ) {
\r
173 rPtr = &Os_Sys.resScheduler;
\r
175 /* Check we can access it */
\r
176 if( (pcbPtr->resourceAccess & (1<< ResID)) == 0 ) {
\r
181 rPtr = Os_CfgGetResource(ResID);
\r
184 /* Check for invalid configuration */
\r
185 if( (rPtr->owner != NO_TASK_OWNER) ||
\r
186 (pcbPtr->prio > rPtr->ceiling_priority) )
\r
189 Irq_Restore(flags);
\r
193 Os_ResourceAlloc(rPtr,pcbPtr);
\r
194 Irq_Restore(flags);
\r
199 OS_STD_END_1(OSServiceId_GetResource,ResID);
\r
203 * ReleaseResource is the counterpart of GetResource and
\r
204 * serves to leave critical sections in the code that are assigned to
\r
205 * the resource referenced by <ResID>.
\r
207 * For information on nesting conditions, see particularities of
\r
208 * GetResource. The service may be called from an ISR and from task level (see
\r
215 StatusType ReleaseResource( ResourceType ResID) {
\r
216 StatusType rv = E_OK;
\r
217 OsPcbType *pcbPtr = Os_TaskGetCurrent();
\r
218 OsResourceType *rPtr;
\r
222 if( ResID == RES_SCHEDULER ) {
\r
223 rPtr = &Os_Sys.resScheduler;
\r
225 /* Check we can access it */
\r
226 if( (pcbPtr->resourceAccess & (1<< ResID)) == 0 ) {
\r
230 rPtr = Os_CfgGetResource(ResID);
\r
233 /* Check for invalid configuration */
\r
234 if( rPtr->owner == NO_TASK_OWNER)
\r
237 Irq_Restore(flags);
\r
241 if( (pcbPtr->prio < rPtr->ceiling_priority))
\r
244 Irq_Restore(flags);
\r
248 Os_ResourceFree(rPtr,pcbPtr);
\r
250 /* do a rescheduling (in some cases) (see OSEK OS 4.6.1) */
\r
251 if ( (pcbPtr->scheduling == FULL) &&
\r
252 (Os_Sys.int_nest_cnt == 0) &&
\r
253 (Os_SchedulerResourceIsFree()) ) {
\r
255 OsPcbType* top_pcb = Os_TaskGetTop();
\r
257 /* only dispatch if some other ready task has higher prio */
\r
258 if (top_pcb->prio > Os_TaskGetCurrent()->prio) {
\r
259 Os_Dispatch(OP_RELEASE_RESOURCE);
\r
262 Irq_Restore(flags);
\r
264 OS_STD_END_1(OSServiceId_ReleaseResource,ResID);
\r
268 void Os_ResourceGetInternal( void ) {
\r
269 OsPcbType *pcbPtr = Os_TaskGetCurrent();
\r
270 OsResourceType *rt = pcbPtr->resource_int_p;
\r
273 OS_DEBUG(D_RESOURCE,"Get IR proc:%s prio:%u old_task_prio:%u\n",
\r
274 get_curr_pcb()->name,
\r
275 (unsigned)rt->ceiling_priority,
\r
276 (unsigned)rt->old_task_prio);
\r
277 Os_ResourceAlloc(rt,pcbPtr);
\r
281 void Os_ResourceReleaseInternal( void ) {
\r
282 OsPcbType *pcbPtr = Os_TaskGetCurrent();
\r
283 OsResourceType *rt = pcbPtr->resource_int_p;
\r
286 OS_DEBUG(D_RESOURCE,"Rel IR proc:%s prio:%u old_task_prio:%u\n",
\r
287 get_curr_pcb()->name,
\r
288 (unsigned)rt->ceiling_priority,
\r
289 (unsigned)rt->old_task_prio);
\r
290 Os_ResourceFree(rt,pcbPtr);
\r
301 void Os_ResourceInit( void ) {
\r
302 //TAILQ_INIT(&pcb_p->resource_head);
\r
304 OsResourceType *rsrc_p;
\r
308 /* For now, assign the scheduler resource here */
\r
309 Os_Sys.resScheduler.ceiling_priority = OS_RES_SCHEDULER_PRIO;
\r
310 strcpy(Os_Sys.resScheduler.id,"RES_SCHEDULER");
\r
311 Os_Sys.resScheduler.nr = RES_SCHEDULER;
\r
312 Os_Sys.resScheduler.owner = NO_TASK_OWNER;
\r
314 /* Calculate ceiling priority
\r
315 * We make this as simple as possible. The ceiling priority
\r
316 * is set to the same priority as the highest priority task that
\r
319 * Note that this applies both internal and standard resources.
\r
321 for( int i=0; i < OS_RESOURCE_CNT; i++) {
\r
322 rsrc_p = Os_CfgGetResource(i);
\r
325 for( int pi = 0; pi < OS_TASK_CNT; pi++) {
\r
327 pcb_p = os_get_pcb(pi);
\r
330 if(pcb_p->resourceAccess & (1<<i) ) {
\r
331 topPrio = MAX(topPrio,pcb_p->prio);
\r
334 /* Generator fix, add RES_SCHEDULER */
\r
335 pcb_p->resourceAccess |= (1 << RES_SCHEDULER) ;
\r
337 rsrc_p->ceiling_priority = topPrio;
\r