Contiki 2.6
|
00001 /* 00002 * Copyright (c) 2005, Swedish Institute of Computer Science 00003 * All rights reserved. 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions 00007 * are met: 00008 * 1. Redistributions of source code must retain the above copyright 00009 * notice, this list of conditions and the following disclaimer. 00010 * 2. Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * 3. Neither the name of the Institute nor the names of its contributors 00014 * may be used to endorse or promote products derived from this software 00015 * without specific prior written permission. 00016 * 00017 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 00018 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00019 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00020 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 00021 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 00022 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 00023 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00024 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00025 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 00026 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 00027 * SUCH DAMAGE. 00028 * 00029 * This file is part of the Contiki operating system. 00030 * 00031 * @(#)$Id: process.c,v 1.12 2010/10/20 22:24:46 adamdunkels Exp $ 00032 */ 00033 00034 /** 00035 * \addtogroup process 00036 * @{ 00037 */ 00038 00039 /** 00040 * \file 00041 * Implementation of the Contiki process kernel. 00042 * \author 00043 * Adam Dunkels <adam@sics.se> 00044 * 00045 */ 00046 00047 #include <stdio.h> 00048 00049 #include "sys/process.h" 00050 #include "sys/arg.h" 00051 00052 /* 00053 * Pointer to the currently running process structure. 00054 */ 00055 struct process *process_list = NULL; 00056 struct process *process_current = NULL; 00057 00058 static process_event_t lastevent; 00059 00060 /* 00061 * Structure used for keeping the queue of active events. 00062 */ 00063 struct event_data { 00064 process_event_t ev; 00065 process_data_t data; 00066 struct process *p; 00067 }; 00068 00069 static process_num_events_t nevents, fevent; 00070 static struct event_data events[PROCESS_CONF_NUMEVENTS]; 00071 00072 #if PROCESS_CONF_STATS 00073 process_num_events_t process_maxevents; 00074 #endif 00075 00076 static volatile unsigned char poll_requested; 00077 00078 #define PROCESS_STATE_NONE 0 00079 #define PROCESS_STATE_RUNNING 1 00080 #define PROCESS_STATE_CALLED 2 00081 00082 static void call_process(struct process *p, process_event_t ev, process_data_t data); 00083 00084 #define DEBUG 0 00085 #if DEBUG 00086 #include <stdio.h> 00087 #define PRINTF(...) printf(__VA_ARGS__) 00088 #else 00089 #define PRINTF(...) 00090 #endif 00091 00092 /*---------------------------------------------------------------------------*/ 00093 process_event_t 00094 process_alloc_event(void) 00095 { 00096 return lastevent++; 00097 } 00098 /*---------------------------------------------------------------------------*/ 00099 void 00100 process_start(struct process *p, const char *arg) 00101 { 00102 struct process *q; 00103 00104 /* First make sure that we don't try to start a process that is 00105 already running. */ 00106 for(q = process_list; q != p && q != NULL; q = q->next); 00107 00108 /* If we found the process on the process list, we bail out. */ 00109 if(q == p) { 00110 return; 00111 } 00112 /* Put on the procs list.*/ 00113 p->next = process_list; 00114 process_list = p; 00115 p->state = PROCESS_STATE_RUNNING; 00116 PT_INIT(&p->pt); 00117 00118 PRINTF("process: starting '%s'\n", PROCESS_NAME_STRING(p)); 00119 00120 /* Post a synchronous initialization event to the process. */ 00121 process_post_synch(p, PROCESS_EVENT_INIT, (process_data_t)arg); 00122 } 00123 /*---------------------------------------------------------------------------*/ 00124 static void 00125 exit_process(struct process *p, struct process *fromprocess) 00126 { 00127 register struct process *q; 00128 struct process *old_current = process_current; 00129 00130 PRINTF("process: exit_process '%s'\n", PROCESS_NAME_STRING(p)); 00131 00132 /* Make sure the process is in the process list before we try to 00133 exit it. */ 00134 for(q = process_list; q != p && q != NULL; q = q->next); 00135 if(q == NULL) { 00136 return; 00137 } 00138 00139 if(process_is_running(p)) { 00140 /* Process was running */ 00141 p->state = PROCESS_STATE_NONE; 00142 00143 /* 00144 * Post a synchronous event to all processes to inform them that 00145 * this process is about to exit. This will allow services to 00146 * deallocate state associated with this process. 00147 */ 00148 for(q = process_list; q != NULL; q = q->next) { 00149 if(p != q) { 00150 call_process(q, PROCESS_EVENT_EXITED, (process_data_t)p); 00151 } 00152 } 00153 00154 if(p->thread != NULL && p != fromprocess) { 00155 /* Post the exit event to the process that is about to exit. */ 00156 process_current = p; 00157 p->thread(&p->pt, PROCESS_EVENT_EXIT, NULL); 00158 } 00159 } 00160 00161 if(p == process_list) { 00162 process_list = process_list->next; 00163 } else { 00164 for(q = process_list; q != NULL; q = q->next) { 00165 if(q->next == p) { 00166 q->next = p->next; 00167 break; 00168 } 00169 } 00170 } 00171 00172 process_current = old_current; 00173 } 00174 /*---------------------------------------------------------------------------*/ 00175 static void 00176 call_process(struct process *p, process_event_t ev, process_data_t data) 00177 { 00178 int ret; 00179 00180 #if DEBUG 00181 if(p->state == PROCESS_STATE_CALLED) { 00182 printf("process: process '%s' called again with event %d\n", PROCESS_NAME_STRING(p), ev); 00183 } 00184 #endif /* DEBUG */ 00185 00186 if((p->state & PROCESS_STATE_RUNNING) && 00187 p->thread != NULL) { 00188 PRINTF("process: calling process '%s' with event %d\n", PROCESS_NAME_STRING(p), ev); 00189 process_current = p; 00190 p->state = PROCESS_STATE_CALLED; 00191 ret = p->thread(&p->pt, ev, data); 00192 if(ret == PT_EXITED || 00193 ret == PT_ENDED || 00194 ev == PROCESS_EVENT_EXIT) { 00195 exit_process(p, p); 00196 } else { 00197 p->state = PROCESS_STATE_RUNNING; 00198 } 00199 } 00200 } 00201 /*---------------------------------------------------------------------------*/ 00202 void 00203 process_exit(struct process *p) 00204 { 00205 exit_process(p, PROCESS_CURRENT()); 00206 } 00207 /*---------------------------------------------------------------------------*/ 00208 void 00209 process_init(void) 00210 { 00211 lastevent = PROCESS_EVENT_MAX; 00212 00213 nevents = fevent = 0; 00214 #if PROCESS_CONF_STATS 00215 process_maxevents = 0; 00216 #endif /* PROCESS_CONF_STATS */ 00217 00218 process_current = process_list = NULL; 00219 } 00220 /*---------------------------------------------------------------------------*/ 00221 /* 00222 * Call each process' poll handler. 00223 */ 00224 /*---------------------------------------------------------------------------*/ 00225 static void 00226 do_poll(void) 00227 { 00228 struct process *p; 00229 00230 poll_requested = 0; 00231 /* Call the processes that needs to be polled. */ 00232 for(p = process_list; p != NULL; p = p->next) { 00233 if(p->needspoll) { 00234 p->state = PROCESS_STATE_RUNNING; 00235 p->needspoll = 0; 00236 call_process(p, PROCESS_EVENT_POLL, NULL); 00237 } 00238 } 00239 } 00240 /*---------------------------------------------------------------------------*/ 00241 /* 00242 * Process the next event in the event queue and deliver it to 00243 * listening processes. 00244 */ 00245 /*---------------------------------------------------------------------------*/ 00246 static void 00247 do_event(void) 00248 { 00249 static process_event_t ev; 00250 static process_data_t data; 00251 static struct process *receiver; 00252 static struct process *p; 00253 00254 /* 00255 * If there are any events in the queue, take the first one and walk 00256 * through the list of processes to see if the event should be 00257 * delivered to any of them. If so, we call the event handler 00258 * function for the process. We only process one event at a time and 00259 * call the poll handlers inbetween. 00260 */ 00261 00262 if(nevents > 0) { 00263 00264 /* There are events that we should deliver. */ 00265 ev = events[fevent].ev; 00266 00267 data = events[fevent].data; 00268 receiver = events[fevent].p; 00269 00270 /* Since we have seen the new event, we move pointer upwards 00271 and decrese the number of events. */ 00272 fevent = (fevent + 1) % PROCESS_CONF_NUMEVENTS; 00273 --nevents; 00274 00275 /* If this is a broadcast event, we deliver it to all events, in 00276 order of their priority. */ 00277 if(receiver == PROCESS_BROADCAST) { 00278 for(p = process_list; p != NULL; p = p->next) { 00279 00280 /* If we have been requested to poll a process, we do this in 00281 between processing the broadcast event. */ 00282 if(poll_requested) { 00283 do_poll(); 00284 } 00285 call_process(p, ev, data); 00286 } 00287 } else { 00288 /* This is not a broadcast event, so we deliver it to the 00289 specified process. */ 00290 /* If the event was an INIT event, we should also update the 00291 state of the process. */ 00292 if(ev == PROCESS_EVENT_INIT) { 00293 receiver->state = PROCESS_STATE_RUNNING; 00294 } 00295 00296 /* Make sure that the process actually is running. */ 00297 call_process(receiver, ev, data); 00298 } 00299 } 00300 } 00301 /*---------------------------------------------------------------------------*/ 00302 int 00303 process_run(void) 00304 { 00305 /* Process poll events. */ 00306 if(poll_requested) { 00307 do_poll(); 00308 } 00309 00310 /* Process one event from the queue */ 00311 do_event(); 00312 00313 return nevents + poll_requested; 00314 } 00315 /*---------------------------------------------------------------------------*/ 00316 int 00317 process_nevents(void) 00318 { 00319 return nevents + poll_requested; 00320 } 00321 /*---------------------------------------------------------------------------*/ 00322 int 00323 process_post(struct process *p, process_event_t ev, process_data_t data) 00324 { 00325 static process_num_events_t snum; 00326 00327 if(PROCESS_CURRENT() == NULL) { 00328 PRINTF("process_post: NULL process posts event %d to process '%s', nevents %d\n", 00329 ev,PROCESS_NAME_STRING(p), nevents); 00330 } else { 00331 PRINTF("process_post: Process '%s' posts event %d to process '%s', nevents %d\n", 00332 PROCESS_NAME_STRING(PROCESS_CURRENT()), ev, 00333 p == PROCESS_BROADCAST? "<broadcast>": PROCESS_NAME_STRING(p), nevents); 00334 } 00335 00336 if(nevents == PROCESS_CONF_NUMEVENTS) { 00337 #if DEBUG 00338 if(p == PROCESS_BROADCAST) { 00339 printf("soft panic: event queue is full when broadcast event %d was posted from %s\n", ev, PROCESS_NAME_STRING(process_current)); 00340 } else { 00341 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)); 00342 } 00343 #endif /* DEBUG */ 00344 return PROCESS_ERR_FULL; 00345 } 00346 00347 snum = (process_num_events_t)(fevent + nevents) % PROCESS_CONF_NUMEVENTS; 00348 events[snum].ev = ev; 00349 events[snum].data = data; 00350 events[snum].p = p; 00351 ++nevents; 00352 00353 #if PROCESS_CONF_STATS 00354 if(nevents > process_maxevents) { 00355 process_maxevents = nevents; 00356 } 00357 #endif /* PROCESS_CONF_STATS */ 00358 00359 return PROCESS_ERR_OK; 00360 } 00361 /*---------------------------------------------------------------------------*/ 00362 void 00363 process_post_synch(struct process *p, process_event_t ev, process_data_t data) 00364 { 00365 struct process *caller = process_current; 00366 00367 call_process(p, ev, data); 00368 process_current = caller; 00369 } 00370 /*---------------------------------------------------------------------------*/ 00371 void 00372 process_poll(struct process *p) 00373 { 00374 if(p != NULL) { 00375 if(p->state == PROCESS_STATE_RUNNING || 00376 p->state == PROCESS_STATE_CALLED) { 00377 p->needspoll = 1; 00378 poll_requested = 1; 00379 } 00380 } 00381 } 00382 /*---------------------------------------------------------------------------*/ 00383 int 00384 process_is_running(struct process *p) 00385 { 00386 return p->state != PROCESS_STATE_NONE; 00387 } 00388 /*---------------------------------------------------------------------------*/ 00389 /** @} */