EVE 1.0
process.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2005, Swedish Institute of Computer Science
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * This file is part of the Contiki operating system.
30  *
31  */
32 
33 /**
34  * \file
35  * Implementation of the Contiki process kernel.
36  * \author
37  * Adam Dunkels <adam@sics.se>
38  *
39  */
40 
41 #include <stdio.h>
42 #include <app_util_platform.h>
43 #include <nrf_nvic.h>
44 #include <core/pm.h>
45 
46 #include "sys/process.h"
47 #include "sys/arg.h"
48 
49 /*
50  * Pointer to the currently running process structure.
51  */
52 struct process *process_list = NULL;
53 struct process *process_current = NULL;
54 
55 static process_event_t lastevent;
56 
57 /*
58  * Structure used for keeping the queue of active events.
59  */
60 struct event_data {
61  process_event_t ev;
62  process_data_t data;
63  struct process *p;
64 };
65 
66 static volatile process_num_events_t nevents;
67 static volatile process_num_events_t fevent;
68 static volatile struct event_data events[PROCESS_CONF_NUMEVENTS];
69 
70 #if PROCESS_CONF_STATS
71 process_num_events_t process_maxevents;
72 #endif
73 
74 static volatile unsigned char poll_requested;
75 
76 #define PROCESS_STATE_NONE 0
77 #define PROCESS_STATE_RUNNING 1
78 #define PROCESS_STATE_CALLED 2
79 
80 static void call_process(struct process *p, process_event_t ev, process_data_t data);
81 
82 #ifndef DEBUG
83  #define DEBUG 0
84 #endif
85 #if DEBUG
86 #include <stdio.h>
87 #define PRINTF(...) printf(__VA_ARGS__)
88 #else
89 #define PRINTF(...)
90 #endif
91 
92 /*---------------------------------------------------------------------------*/
93 process_event_t
95 {
96  return lastevent++;
97 }
98 /*---------------------------------------------------------------------------*/
99 void
100 process_start(struct process *p, const char *arg)
101 {
102  struct process *q;
103 
104  /* First make sure that we don't try to start a process that is
105  already running. */
106  for(q = process_list; q != p && q != NULL; q = q->next);
107 
108  /* If we found the process on the process list, we bail out. */
109  if(q == p) {
110  return;
111  }
112  /* Put on the procs list.*/
113  p->next = process_list;
114  process_list = p;
115  p->state = PROCESS_STATE_RUNNING;
116  PT_INIT(&p->pt);
117 
118  PRINTF("process: starting '%s'\n", PROCESS_NAME_STRING(p));
119 
120  /* Post a synchronous initialization event to the process. */
121  process_post_synch(p, PROCESS_EVENT_INIT, (process_data_t)arg);
122 }
123 /*---------------------------------------------------------------------------*/
124 static void
125 exit_process(struct process *p, struct process *fromprocess)
126 {
127  register struct process *q;
128  struct process *old_current = process_current;
129 
130  PRINTF("process: exit_process '%s'\n", PROCESS_NAME_STRING(p));
131 
132  /* Make sure the process is in the process list before we try to
133  exit it. */
134  for(q = process_list; q != p && q != NULL; q = q->next);
135  if(q == NULL) {
136  return;
137  }
138 
139  if(process_is_running(p)) {
140  /* Process was running */
141  p->state = PROCESS_STATE_NONE;
142 
143  /*
144  * Post a synchronous event to all processes to inform them that
145  * this process is about to exit. This will allow services to
146  * deallocate state associated with this process.
147  */
148  for(q = process_list; q != NULL; q = q->next) {
149  if(p != q) {
150  call_process(q, PROCESS_EVENT_EXITED, (process_data_t)p);
151  }
152  }
153 
154  if(p->thread != NULL && p != fromprocess) {
155  /* Post the exit event to the process that is about to exit. */
156  process_current = p;
157  p->thread(&p->pt, PROCESS_EVENT_EXIT, NULL);
158  }
159  }
160 
161  if(p == process_list) {
162  process_list = process_list->next;
163  } else {
164  for(q = process_list; q != NULL; q = q->next) {
165  if(q->next == p) {
166  q->next = p->next;
167  break;
168  }
169  }
170  }
171 
172  process_current = old_current;
173 }
174 /*---------------------------------------------------------------------------*/
175 static void
176 call_process(struct process *p, process_event_t ev, process_data_t data)
177 {
178  int ret;
179 
180 #if DEBUG
181  if(p->state == PROCESS_STATE_CALLED) {
182  printf("process: process '%s' called again with event %d\n", PROCESS_NAME_STRING(p), ev);
183  }
184 #endif /* DEBUG */
185 
186  if((p->state & PROCESS_STATE_RUNNING) &&
187  p->thread != NULL) {
188  PRINTF("process: calling process '%s' with event %d\n", PROCESS_NAME_STRING(p), ev);
189  process_current = p;
190  p->state = PROCESS_STATE_CALLED;
191  ret = p->thread(&p->pt, ev, data);
192  if(ret == PT_EXITED ||
193  ret == PT_ENDED ||
194  ev == PROCESS_EVENT_EXIT) {
195  exit_process(p, p);
196  } else {
197  p->state = PROCESS_STATE_RUNNING;
198  }
199  }
200 }
201 /*---------------------------------------------------------------------------*/
202 void
203 process_exit(struct process *p)
204 {
205  exit_process(p, PROCESS_CURRENT());
206 }
207 /*---------------------------------------------------------------------------*/
208 void
210 {
211  lastevent = PROCESS_EVENT_MAX;
212 
213  nevents = fevent = 0;
214 #if PROCESS_CONF_STATS
215  process_maxevents = 0;
216 #endif /* PROCESS_CONF_STATS */
217 
218  process_current = process_list = NULL;
219 }
220 /*---------------------------------------------------------------------------*/
221 /*
222  * Call each process' poll handler.
223  */
224 /*---------------------------------------------------------------------------*/
225 static void
226 do_poll(void)
227 {
228  struct process *p;
229 
230  poll_requested = 0;
231  /* Call the processes that needs to be polled. */
232  for(p = process_list; p != NULL; p = p->next) {
233  if(p->needspoll) {
234  p->state = PROCESS_STATE_RUNNING;
235  p->needspoll = 0;
236  call_process(p, PROCESS_EVENT_POLL, NULL);
237  }
238  }
239 }
240 /*---------------------------------------------------------------------------*/
241 /*
242  * Process the next event in the event queue and deliver it to
243  * listening processes.
244  */
245 /*---------------------------------------------------------------------------*/
246 static void
247 do_event(void)
248 {
249  static process_event_t ev;
250  static process_data_t data;
251  static struct process *receiver;
252  static struct process *p;
253 
254  /*
255  * If there are any events in the queue, take the first one and walk
256  * through the list of processes to see if the event should be
257  * delivered to any of them. If so, we call the event handler
258  * function for the process. We only process one event at a time and
259  * call the poll handlers inbetween.
260  */
261 
262  if(nevents > 0) {
263 
264  CRITICAL_REGION_ENTER();
265 
266  /* There are events that we should deliver. */
267  ev = events[fevent].ev;
268 
269  data = events[fevent].data;
270  receiver = events[fevent].p;
271 
272  /* Since we have seen the new event, we move pointer upwards
273  and decrese the number of events. */
274  fevent = (fevent + 1) % PROCESS_CONF_NUMEVENTS;
275  --nevents;
276 
277  CRITICAL_REGION_EXIT();
278 
279  /* If this is a broadcast event, we deliver it to all events, in
280  order of their priority. */
281  if(receiver == PROCESS_BROADCAST) {
282  for(p = process_list; p != NULL; p = p->next) {
283 
284  /* If we have been requested to poll a process, we do this in
285  between processing the broadcast event. */
286  if(poll_requested) {
287  do_poll();
288  }
289  call_process(p, ev, data);
290  }
291  } else {
292  /* This is not a broadcast event, so we deliver it to the
293  specified process. */
294  /* If the event was an INIT event, we should also update the
295  state of the process. */
296  if(ev == PROCESS_EVENT_INIT) {
297  receiver->state = PROCESS_STATE_RUNNING;
298  }
299 
300  /* Make sure that the process actually is running. */
301  call_process(receiver, ev, data);
302  }
303  }
304 }
305 /*---------------------------------------------------------------------------*/
306 int
308 {
309  /* Process poll events. */
310  if(poll_requested) {
311  do_poll();
312  }
313 
314  /* Process one event from the queue */
315  do_event();
316 
317  return nevents + poll_requested;
318 }
319 /*---------------------------------------------------------------------------*/
320 int
322 {
323  return nevents + poll_requested;
324 }
325 /*---------------------------------------------------------------------------*/
326 int
327 process_post(struct process *p, process_event_t ev, process_data_t data)
328 {
329  static process_num_events_t snum;
330  int ret;
331 
332  if(PROCESS_CURRENT() == NULL) {
333  PRINTF("process_post: NULL process posts event %d to process '%s', nevents %d\n",
334  ev,PROCESS_NAME_STRING(p), nevents);
335  } else {
336  PRINTF("process_post: Process '%s' posts event %d to process '%s', nevents %d\n",
337  PROCESS_NAME_STRING(PROCESS_CURRENT()), ev,
338  p == PROCESS_BROADCAST? "<broadcast>": PROCESS_NAME_STRING(p), nevents);
339  }
340 
341  CRITICAL_REGION_ENTER();
342  if(nevents == PROCESS_CONF_NUMEVENTS) {
343 //#if DEBUG
344  if(p == PROCESS_BROADCAST) {
345  printf("soft panic: event queue is full when broadcast event %d was posted from %s\n", ev, PROCESS_NAME_STRING(process_current));
346  } else {
347  printf("soft panic: event queue is full when event %d was posted to %s frpm %s\n", ev, PROCESS_NAME_STRING(p), PROCESS_NAME_STRING(process_current));
348  }
349 //#endif /* DEBUG */
350  ret = PROCESS_ERR_FULL;
351  } else {
352  snum = (process_num_events_t)(fevent + nevents) % PROCESS_CONF_NUMEVENTS;
353  events[snum].ev = ev;
354  events[snum].data = data;
355  events[snum].p = p;
356  ++nevents;
357 
358  #if PROCESS_CONF_STATS
359  if(nevents > process_maxevents) {
360  process_maxevents = nevents;
361  }
362  #endif /* PROCESS_CONF_STATS */
363  ret = PROCESS_ERR_OK;
364  }
365 
366  pm_wakeup();
367 
368  CRITICAL_REGION_EXIT();
369 
370  return ret;
371 }
372 /*---------------------------------------------------------------------------*/
373 void
374 process_post_synch(struct process *p, process_event_t ev, process_data_t data)
375 {
376  struct process *caller = process_current;
377 
378  call_process(p, ev, data);
379  process_current = caller;
380 }
381 /*---------------------------------------------------------------------------*/
382 int
383 process_abort_event(struct process *p, process_event_t ev, void **pdata)
384 {
385  int ret = 0;
386  CRITICAL_REGION_ENTER();
387  {
388  process_num_events_t index = fevent;
389  process_num_events_t count = nevents;
390  process_num_events_t next;
391 
392  /* Search for the event */
393  for (; count != 0; index = next, --count) {
394  next = (index + 1) % PROCESS_CONF_NUMEVENTS;
395  if (events[index].p != p || events[index].ev != ev)
396  continue;
397  if (pdata)
398  *pdata = events[index].data;
399  --nevents;
400  ret = true;
401  break;
402  }
403 
404  /* Move down the rest of the queue */
405  for (; count > 1; index = next, --count) {
406  next = (index + 1) % PROCESS_CONF_NUMEVENTS;
407  events[index] = events[next];
408  }
409  }
410  CRITICAL_REGION_EXIT();
411 
412  return ret;
413 }
414 /*---------------------------------------------------------------------------*/
415 void
416 process_poll(struct process *p)
417 {
418  if(p != NULL) {
419  if(p->state == PROCESS_STATE_RUNNING ||
420  p->state == PROCESS_STATE_CALLED) {
421  p->needspoll = 1;
422  poll_requested = 1;
423  pm_wakeup();
424  }
425  }
426 }
427 /*---------------------------------------------------------------------------*/
428 int
429 process_is_running(struct process *p)
430 {
431  return p->state != PROCESS_STATE_NONE;
432 }
433 /*---------------------------------------------------------------------------*/
#define PT_INIT(pt)
Definition: pt.h:79
void process_poll(struct process *p)
Definition: process.c:416
void process_start(struct process *p, const char *arg)
Definition: process.c:100
void process_exit(struct process *p)
Cause a process to exit.
Definition: process.c:203
process_event_t process_alloc_event(void)
Allocate a global event number.
Definition: process.c:94
Header file for the EVE power management framework.
int process_abort_event(struct process *p, process_event_t ev, void **pdata)
Definition: process.c:383
#define PROCESS_ERR_FULL
Return value indicating that the event queue was full.
Definition: process.h:82
#define PROCESS_ERR_OK
Return value indicating that an operation was successful.
Definition: process.h:74
#define PROCESS_CURRENT()
Definition: process.h:437
int process_post(struct process *p, process_event_t ev, process_data_t data)
Definition: process.c:327
void process_init(void)
Initialize the process module.
Definition: process.c:209
uint8_t data[USBNET_RX_BUF_SIZE]
Definition: usbnet.h:140
int process_nevents(void)
Definition: process.c:321
void pm_wakeup(void)
void process_post_synch(struct process *p, process_event_t ev, process_data_t data)
Definition: process.c:374
int process_is_running(struct process *p)
Definition: process.c:429
int process_run(void)
Definition: process.c:307