]> rtime.felk.cvut.cz Git - arc.git/blob - system/kernel/event.c
e7f07038faad28ca4a834779584d443590aa52e3
[arc.git] / system / kernel / event.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 <sys/queue.h>\r
17 #include <stdlib.h>\r
18 #include "Os.h"\r
19 #include "internal.h"\r
20 \r
21 #define VALIDATE_W_RV(_exp,_rv) \\r
22         if( (_exp) ) { \\r
23                 ERRORHOOK(_rv); \\r
24                 return _rv; \\r
25         }\r
26 \r
27 \r
28 /**\r
29  * The state of the calling task is set to waiting, unless at least one\r
30  * of the events specified in <Mask> has already been set.\r
31  *\r
32  * This call enforces rescheduling, if the wait condition occurs. If\r
33  * rescheduling takes place, the internal resource of the task is\r
34  * released while the task is in the waiting state.\r
35  * This service shall only be called from the extended task owning\r
36  * the event.\r
37  *\r
38  * @param Mask Mask of the events waited for\r
39  * @return\r
40  */\r
41 \r
42 StatusType WaitEvent( EventMaskType Mask ) {\r
43 \r
44         OsPcbType *curr_pcb = get_curr_pcb();\r
45         StatusType rv = E_OK;\r
46 \r
47         OS_DEBUG(D_EVENT,"# WaitEvent %s\n",Os_TaskGetCurrent()->name);\r
48 \r
49         if( os_sys.int_nest_cnt != 0 ) {\r
50                 rv =  E_OS_CALLEVEL;\r
51                 goto err;\r
52         }\r
53 \r
54         if (curr_pcb->proc_type != PROC_EXTENDED) {\r
55                 rv = E_OS_ACCESS;\r
56                 goto err;\r
57         }\r
58 \r
59         if ( Os_TaskOccupiesResources(curr_pcb) ) {\r
60                 rv = E_OS_RESOURCE;\r
61                 goto err;\r
62         }\r
63 \r
64         /* Remove from ready queue */\r
65         Irq_Disable();\r
66 \r
67         // OSEK/VDX footnote 5. The call of WaitEvent does not lead to a waiting state if one of the events passed in the event mask to\r
68     // WaitEvent is already set. In this case WaitEvent does not lead to a rescheduling.\r
69         if( !(curr_pcb->ev_set & Mask) ) {\r
70 \r
71                 curr_pcb->ev_wait = Mask;\r
72 \r
73                 if ( Os_SchedulerResourceIsFree() ) {\r
74                         // Os_TaskMakeWaiting(curr_pcb);\r
75                         Os_Dispatch(OP_WAIT_EVENT);\r
76                         assert( curr_pcb->state & ST_RUNNING );\r
77                 } else {\r
78                         Os_TaskMakeWaiting(curr_pcb);\r
79                 }\r
80         }\r
81 \r
82         Irq_Enable();\r
83 \r
84         // The following line disables the unused label warning. Remove when\r
85         // proper error handling is implemented.\r
86         if (0) goto err;\r
87 \r
88         OS_STD_END_1(OSServiceId_WaitEvent,Mask);\r
89 }\r
90 \r
91 /**\r
92  * The events of task <TaskID> are set according to the event\r
93  * mask <Mask>. Calling SetEvent causes the task <TaskID> to\r
94  * be transferred to the  ready state, if it was waiting for at least\r
95  * one of the events specified in <Mask>.\r
96  *\r
97  * @param TaskID - Reference to the task for which one or several events are to be set.\r
98  * @param Mask - Mask of the events to be set\r
99  * @return\r
100  */\r
101 \r
102 StatusType SetEvent( TaskType TaskID, EventMaskType Mask ) {\r
103         StatusType rv = E_OK;\r
104         OsPcbType *dest_pcb;\r
105         OsPcbType *currPcbPtr;\r
106         uint32_t flags;\r
107 \r
108         OS_DEBUG(D_EVENT,"# SetEvent %s\n",Os_TaskGetCurrent()->name);\r
109 \r
110         if( TaskID  >= OS_TASK_CNT ) {\r
111                 rv = E_OS_ID;\r
112                 goto err;\r
113         }\r
114 \r
115         dest_pcb = os_get_pcb(TaskID);\r
116 \r
117 #if (OS_STATUS_EXTENDED == STD_ON )\r
118         if( dest_pcb->proc_type != PROC_EXTENDED ) {\r
119                 rv = E_OS_ACCESS;\r
120                 goto err;\r
121         }\r
122 \r
123         if( (dest_pcb->state & ST_SUSPENDED ) ) {\r
124                 rv = E_OS_STATE;\r
125                 goto err;\r
126         }\r
127 #endif\r
128 \r
129         Irq_Save(flags);\r
130 \r
131         /* Calling  SetEvent  causes  the  task  <TaskID>  to be  transferred\r
132          * to  the  ready  state,  if  it  was  waiting  for  at  least one of the\r
133          * events specified in <Mask>.\r
134          *\r
135          * OSEK/VDX 4.6.1,  rescheduling is performed in all of the following cases:\r
136          * ..\r
137          * Setting an event to a waiting task at task level (e.g. system service SetEvent,\r
138          * see chapter 13.5.3.1, message notification mechanism, alarm expiration, if event setting\r
139          * defined, see chapter 9.2)\r
140          * ... */\r
141 \r
142         dest_pcb->ev_set |= Mask;\r
143 \r
144         if( (Mask & dest_pcb->ev_wait) ) {\r
145                 /* We have an event match */\r
146                 if( dest_pcb->state & ST_WAITING) {\r
147                         Os_TaskMakeReady(dest_pcb);\r
148 \r
149                         currPcbPtr = Os_TaskGetCurrent();\r
150                         /* Checking "4.6.2  Non preemptive scheduling" it does not dispatch if NON  */\r
151                         if( (os_sys.int_nest_cnt == 0) &&\r
152                                 (currPcbPtr->scheduling == FULL) &&\r
153                                 (dest_pcb->prio > currPcbPtr->prio) &&\r
154                                 (Os_SchedulerResourceIsFree()) )\r
155                         {\r
156                                 Os_Dispatch(OP_SET_EVENT);\r
157                         }\r
158 \r
159                 }  else if(dest_pcb->state & (ST_READY|ST_RUNNING) ) {\r
160                         /* Hmm, we do nothing */\r
161                 } else {\r
162                         assert( 0 );\r
163                 }\r
164         }\r
165 \r
166         Irq_Restore(flags);\r
167 \r
168         OS_STD_END_2(OSServiceId_SetEvent,TaskID, Mask);\r
169 }\r
170 \r
171 \r
172 /**\r
173  * This service returns the current state of all event bits of the task\r
174  * <TaskID>, not the events that the task is waiting for.\r
175  * The service may be called from interrupt service routines, task\r
176  * level and some hook routines (see Figure 12-1).\r
177  *  The current status of the event mask of task <TaskID> is copied\r
178  * to <Event>.\r
179  *\r
180  * @param TaskId Task whose event mask is to be returned.\r
181  * @param Mask   Reference to the memory of the return data.\r
182  * @return\r
183  */\r
184 StatusType GetEvent( TaskType TaskId, EventMaskRefType Mask) {\r
185 \r
186         OsPcbType *dest_pcb;\r
187         StatusType rv = E_OK;\r
188 \r
189         if( TaskId  >= OS_TASK_CNT ) {\r
190                 rv = E_OS_ID;\r
191                 goto err;\r
192         }\r
193 \r
194         dest_pcb = os_get_pcb(TaskId);\r
195 \r
196         VALIDATE_W_RV(dest_pcb->proc_type != PROC_EXTENDED,E_OS_ACCESS);\r
197         VALIDATE_W_RV(dest_pcb->state & ST_SUSPENDED,E_OS_STATE);\r
198 \r
199         *Mask = dest_pcb->ev_set;\r
200 \r
201         if (0) goto err;\r
202 \r
203         OS_STD_END_2(OSServiceId_GetEvent,TaskId, Mask);\r
204 }\r
205 \r
206 \r
207 /**\r
208  * The events of the extended task calling ClearEvent are cleared\r
209  * according to the event mask <Mask>.\r
210  *\r
211  *\r
212  * @param Mask\r
213  * @return\r
214  */\r
215 StatusType ClearEvent( EventMaskType Mask) {\r
216     StatusType rv = E_OK;\r
217         OsPcbType *pcb;\r
218 \r
219         if( os_sys.int_nest_cnt != 0 ) {\r
220                 rv =  E_OS_CALLEVEL;\r
221                 goto err;\r
222         }\r
223 \r
224         pcb = get_curr_pcb();\r
225 \r
226         if (pcb->proc_type != PROC_EXTENDED) {\r
227                 rv = E_OS_ACCESS;\r
228                 goto err;\r
229         }\r
230 \r
231         pcb->ev_set &= ~Mask;\r
232 \r
233         if (0) goto err;\r
234 \r
235         OS_STD_END_1(OSServiceId_ClearEvent,Mask);\r
236 }\r
237 \r
238 \r
239 \r
240 \r
241 \r