adamdunkels | 2764255 | 2004-07-04 11:54:10 +0000 | [diff] [blame] | 1 | /** |
adamdunkels | 442bdc8 | 2005-02-22 22:46:33 +0000 | [diff] [blame] | 2 | * \defgroup ek The Contiki event kernel |
| 3 | * @{ |
| 4 | * |
| 5 | * At the heart of the Contiki desktop environment is the event driven |
| 6 | * Contiki kernel. Using non-preemptive multitasking, the Contiki |
| 7 | * event kernel makes it possible to run several programs in |
| 8 | * parallel. It also provides message passing mechanisms to the |
| 9 | * running programs. |
| 10 | * |
| 11 | * The Contiki kernel is a simple event driven dispatcher which |
| 12 | * handles processes and events. All code execution is |
| 13 | * initiated by the kernel, and applications are implemented as C |
| 14 | * functions that must return within a short time after being |
| 15 | * called. |
| 16 | * |
| 17 | * The kernel does not provide multi-threading. Rather, this is |
| 18 | * implemented as an application library. For threads, see the |
| 19 | * \ref mt "Multithreading library" and \ref pt "Protothreads". |
| 20 | * |
| 21 | * The kernel is the initiator of all program execution in |
| 22 | * Contiki. After the system has been initialized by the boot up code, |
| 23 | * the ek_run() function is called. This function never |
| 24 | * returns, but will sit in a loop in which it does two things. |
| 25 | * |
| 26 | * - Pulls the first event of the event queue and dispatches this to |
| 27 | * all listening processes (ek_process_event()). |
| 28 | * |
| 29 | * - Executes the "poll" handlers of all processes that have |
| 30 | * registered (ek_process_poll()). |
| 31 | * |
| 32 | * Only one event is processes at a time, and the poll handlers of |
| 33 | * all processes are called between two events are handled. |
| 34 | * |
| 35 | * |
| 36 | * A process is defined by an initialization function, a event |
| 37 | * handler, a uIP event handler, and an poll handler. The event |
| 38 | * handler is called when a event has been posted, for which the |
| 39 | * process is currently listening. The uIP event handler is called |
| 40 | * when the uIP TCP/IP stack has an event to deliver to the |
| 41 | * process. Such events can be that new data has arrived on a |
| 42 | * connection, that previously sent data has been acknowledged or that |
| 43 | * a connection has been closed. The poll handler is periodically |
| 44 | * called by the system. |
| 45 | * |
| 46 | * A process is started by calling the ek_start() |
| 47 | * function. This function must be called by the initialization |
| 48 | * function before any other kernel function is called. When the |
| 49 | * function returns, the new process is running. |
| 50 | * |
| 51 | * The initialization function is declared with the special |
| 52 | * LOADER_INIT() macro. The initializaition function takes a single |
| 53 | * argument; a char * pointer. |
| 54 | * |
| 55 | * The function ek_exit() is used to tell the kernel that |
| 56 | * a process has exited. This function must be called by the process |
| 57 | * itself, and must be called the process unloads itself. |
| 58 | * |
| 59 | * \note It is not possible to call ek_exit() on behalf of |
| 60 | * another process - instead, post the event ek_event_quit |
| 61 | * with the process as a receiver. The other process should then |
| 62 | * listen for this event, and call ek_exit() when the event |
| 63 | * is received. |
| 64 | * |
| 65 | * |
| 66 | * The kernel can pass events between different |
| 67 | * processes. Events are simple messages that consist of a event |
| 68 | * number and a generic data pointer called the event data. The |
| 69 | * event data can be used to pass messages between processes. In |
| 70 | * order for a event to be delivered to a process, the process must |
| 71 | * be listening for the event number. |
| 72 | * |
| 73 | * If a process has registered an poll handler, the kernel will |
| 74 | * call it as often as possible. The poll handler can be used to |
| 75 | * implement timer based functionality (by checking the ek_clock() |
| 76 | * function), or other background processing. The poll handler must |
| 77 | * return to the caller within a short time, or otherwise the system |
| 78 | * will become sluggish. |
| 79 | * |
| 80 | * |
| 81 | */ |
| 82 | |
| 83 | |
| 84 | /** |
adamdunkels | 2764255 | 2004-07-04 11:54:10 +0000 | [diff] [blame] | 85 | * \file |
adamdunkels | 442bdc8 | 2005-02-22 22:46:33 +0000 | [diff] [blame] | 86 | * Event kernel. |
adamdunkels | 2764255 | 2004-07-04 11:54:10 +0000 | [diff] [blame] | 87 | * \author Adam Dunkels <adam@dunkels.com> |
| 88 | * |
adamdunkels | 442bdc8 | 2005-02-22 22:46:33 +0000 | [diff] [blame] | 89 | * The kernel in Contiki handles processes and events. All process |
| 90 | * execution is initiated by the kernel. |
adamdunkels | 2764255 | 2004-07-04 11:54:10 +0000 | [diff] [blame] | 91 | */ |
adamdunkels | ca9ddcb | 2003-03-19 14:13:31 +0000 | [diff] [blame] | 92 | /* |
adamdunkels | 2764255 | 2004-07-04 11:54:10 +0000 | [diff] [blame] | 93 | * Copyright (c) 2002-2003, Adam Dunkels. |
adamdunkels | ca9ddcb | 2003-03-19 14:13:31 +0000 | [diff] [blame] | 94 | * All rights reserved. |
| 95 | * |
| 96 | * Redistribution and use in source and binary forms, with or without |
| 97 | * modification, are permitted provided that the following conditions |
| 98 | * are met: |
| 99 | * 1. Redistributions of source code must retain the above copyright |
| 100 | * notice, this list of conditions and the following disclaimer. |
| 101 | * 2. Redistributions in binary form must reproduce the above |
| 102 | * copyright notice, this list of conditions and the following |
| 103 | * disclaimer in the documentation and/or other materials provided |
| 104 | * with the distribution. |
adamdunkels | 2764255 | 2004-07-04 11:54:10 +0000 | [diff] [blame] | 105 | * 3. The name of the author may not be used to endorse or promote |
adamdunkels | ca9ddcb | 2003-03-19 14:13:31 +0000 | [diff] [blame] | 106 | * products derived from this software without specific prior |
| 107 | * written permission. |
| 108 | * |
| 109 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS |
| 110 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| 111 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 112 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
| 113 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| 114 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE |
| 115 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| 116 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| 117 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
| 118 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| 119 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 120 | * |
| 121 | * This file is part of the "ek" event kernel. |
| 122 | * |
ryohji | c615a2d | 2007-06-02 07:32:05 +0000 | [diff] [blame] | 123 | * $Id: ek.c,v 1.9 2007/06/02 07:32:05 ryohji Exp $ |
adamdunkels | ca9ddcb | 2003-03-19 14:13:31 +0000 | [diff] [blame] | 124 | * |
| 125 | */ |
| 126 | |
| 127 | #include "ek.h" |
adamdunkels | ca9ddcb | 2003-03-19 14:13:31 +0000 | [diff] [blame] | 128 | |
adamdunkels | 2764255 | 2004-07-04 11:54:10 +0000 | [diff] [blame] | 129 | #include <string.h> /* for strncmp() */ |
| 130 | |
adamdunkels | 2764255 | 2004-07-04 11:54:10 +0000 | [diff] [blame] | 131 | /** |
| 132 | * \internal Pointer to the currently running process structure. |
| 133 | * |
| 134 | */ |
adamdunkels | d3bccb9 | 2004-08-09 20:36:39 +0000 | [diff] [blame] | 135 | struct ek_proc *ek_procs = NULL; |
adamdunkels | 2764255 | 2004-07-04 11:54:10 +0000 | [diff] [blame] | 136 | struct ek_proc *ek_proclist[EK_CONF_MAXPROCS]; |
adamdunkels | d3bccb9 | 2004-08-09 20:36:39 +0000 | [diff] [blame] | 137 | struct ek_proc *ek_current = NULL; |
| 138 | |
adamdunkels | 2764255 | 2004-07-04 11:54:10 +0000 | [diff] [blame] | 139 | ek_event_t ek_event_quit; |
adamdunkels | 2764255 | 2004-07-04 11:54:10 +0000 | [diff] [blame] | 140 | ek_event_t ek_event_msg; |
adamdunkels | 2764255 | 2004-07-04 11:54:10 +0000 | [diff] [blame] | 141 | |
| 142 | static ek_event_t lastevent; |
| 143 | |
| 144 | #if CC_FUNCTION_POINTER_ARGS |
adamdunkels | d3bccb9 | 2004-08-09 20:36:39 +0000 | [diff] [blame] | 145 | |
adamdunkels | 2764255 | 2004-07-04 11:54:10 +0000 | [diff] [blame] | 146 | #else /* CC_FUNCTION_POINTER_ARGS */ |
| 147 | ek_event_t ek_eventhandler_s; |
| 148 | ek_data_t ek_eventhandler_data; |
adamdunkels | 2764255 | 2004-07-04 11:54:10 +0000 | [diff] [blame] | 149 | #endif /* CC_FUNCTION_POINTER_ARGS */ |
| 150 | |
| 151 | |
| 152 | /** |
| 153 | * \internal Structure used for keeping the queue of active events. |
| 154 | */ |
| 155 | struct event_data { |
| 156 | ek_event_t s; |
| 157 | ek_data_t data; |
| 158 | ek_id_t id; |
| 159 | }; |
| 160 | |
| 161 | static ek_num_events_t nevents, fevent; |
| 162 | static struct event_data events[EK_CONF_NUMEVENTS]; |
| 163 | |
adamdunkels | 5acd9ef | 2004-09-01 18:19:43 +0000 | [diff] [blame] | 164 | volatile unsigned char ek_poll_request; |
adamdunkels | 2764255 | 2004-07-04 11:54:10 +0000 | [diff] [blame] | 165 | |
| 166 | |
adamdunkels | ca9ddcb | 2003-03-19 14:13:31 +0000 | [diff] [blame] | 167 | /*-----------------------------------------------------------------------------------*/ |
adamdunkels | 2764255 | 2004-07-04 11:54:10 +0000 | [diff] [blame] | 168 | /** |
| 169 | * Allocates a event number. |
| 170 | * |
| 171 | * \return The allocated event number or EK_EVENT_NONE if no event |
| 172 | * number could be allocated. |
| 173 | */ |
| 174 | /*-----------------------------------------------------------------------------------*/ |
| 175 | ek_event_t |
| 176 | ek_alloc_event(void) |
| 177 | { |
| 178 | return lastevent++; |
| 179 | } |
| 180 | /*-----------------------------------------------------------------------------------*/ |
| 181 | static void |
| 182 | procs_add(struct ek_proc *p) |
| 183 | { |
adamdunkels | 5acd9ef | 2004-09-01 18:19:43 +0000 | [diff] [blame] | 184 | static struct ek_proc *q, *r; |
PulkoMandy | bcf4d09 | 2014-06-28 17:11:23 +0200 | [diff] [blame^] | 185 | |
adamdunkels | 2764255 | 2004-07-04 11:54:10 +0000 | [diff] [blame] | 186 | /* The process should be placed on the process list according to the |
| 187 | process' priority. The higher the priority, the earlier on the |
| 188 | list. */ |
adamdunkels | 5acd9ef | 2004-09-01 18:19:43 +0000 | [diff] [blame] | 189 | r = NULL; |
| 190 | for(q = ek_procs; q != NULL; q = q->next) { |
PulkoMandy | bcf4d09 | 2014-06-28 17:11:23 +0200 | [diff] [blame^] | 191 | if(q->prio < p->prio) { |
| 192 | if(r) { |
| 193 | r->next = p; |
adamdunkels | 5acd9ef | 2004-09-01 18:19:43 +0000 | [diff] [blame] | 194 | } else { |
PulkoMandy | bcf4d09 | 2014-06-28 17:11:23 +0200 | [diff] [blame^] | 195 | ek_procs = p; |
adamdunkels | 5acd9ef | 2004-09-01 18:19:43 +0000 | [diff] [blame] | 196 | } |
PulkoMandy | bcf4d09 | 2014-06-28 17:11:23 +0200 | [diff] [blame^] | 197 | p->next = q; |
adamdunkels | 5acd9ef | 2004-09-01 18:19:43 +0000 | [diff] [blame] | 198 | return; |
| 199 | } |
| 200 | r = q; |
| 201 | } |
| 202 | |
| 203 | if(q == NULL) { |
| 204 | if(r == NULL) { |
| 205 | p->next = ek_procs; |
| 206 | ek_procs = p; |
| 207 | } else { |
| 208 | r->next = p; |
| 209 | p->next = NULL; |
| 210 | } |
| 211 | } |
PulkoMandy | bcf4d09 | 2014-06-28 17:11:23 +0200 | [diff] [blame^] | 212 | |
adamdunkels | 2764255 | 2004-07-04 11:54:10 +0000 | [diff] [blame] | 213 | |
adamdunkels | 2764255 | 2004-07-04 11:54:10 +0000 | [diff] [blame] | 214 | } |
| 215 | /*-----------------------------------------------------------------------------------*/ |
| 216 | /** |
| 217 | * Starts a new process. |
| 218 | * |
| 219 | * Is called by a program in order to start a new process for the |
| 220 | * program. This function should be called quite early in the |
| 221 | * initialization procedure of a new process. In partcular, it must be |
| 222 | * called before any other dispatcher functions, or functions of other |
| 223 | * modules that make use of dispatcher functions. Most CTK functions |
| 224 | * call dispatcher functions, and should therefore not be called |
| 225 | * before ek_start() is called. |
| 226 | * |
| 227 | * Example: |
| 228 | \code |
| 229 | static void app_poll(void); |
| 230 | static EK_EVENTHANDLER(app_eventhandler, s, data); |
| 231 | static struct ek_proc p = |
| 232 | {EK_PROC("Generic applications", app_poll, app_eventhandler, NULL)}; |
| 233 | static ek_id_t id = EK_ID_NONE; |
| 234 | |
| 235 | LOADER_INIT_FUNC(app_init, arg) |
| 236 | { |
| 237 | arg_free(arg); |
| 238 | |
| 239 | if(id == EK_ID_NONE) { |
| 240 | id = ek_start(&p); |
| 241 | |
| 242 | rest_of_initialization(); |
| 243 | } |
| 244 | } |
| 245 | \endcode |
| 246 | * |
| 247 | * \param p A pointer to a ek_proc struct that must be found |
| 248 | * in the process own memory space. |
| 249 | * |
| 250 | * \return The process identifier for the new process or EK_ID_NONE |
| 251 | * if the process could not be started. |
| 252 | */ |
| 253 | /*-----------------------------------------------------------------------------------*/ |
| 254 | ek_id_t |
| 255 | ek_start(CC_REGISTER_ARG struct ek_proc *p) |
| 256 | { |
| 257 | ek_id_t id; |
| 258 | |
ryohji | c615a2d | 2007-06-02 07:32:05 +0000 | [diff] [blame] | 259 | for(id = 0; id < EK_CONF_MAXPROCS; ++id) { |
adamdunkels | 2764255 | 2004-07-04 11:54:10 +0000 | [diff] [blame] | 260 | if(ek_proclist[id] == NULL) { |
| 261 | break; |
| 262 | } |
| 263 | } |
| 264 | if(id == EK_CONF_MAXPROCS) { |
| 265 | return EK_ID_NONE; |
| 266 | } |
| 267 | |
| 268 | ek_proclist[id] = p; |
| 269 | |
| 270 | /* Put on the procs list.*/ |
| 271 | procs_add(p); |
| 272 | |
| 273 | p->id = id; |
| 274 | |
| 275 | /* Post an asynchronous event to the process. */ |
| 276 | ek_post(id, EK_EVENT_INIT, p); |
PulkoMandy | bcf4d09 | 2014-06-28 17:11:23 +0200 | [diff] [blame^] | 277 | |
adamdunkels | 2764255 | 2004-07-04 11:54:10 +0000 | [diff] [blame] | 278 | return id; |
| 279 | } |
| 280 | /*-----------------------------------------------------------------------------------*/ |
| 281 | /** |
| 282 | * Exit the currently running process |
| 283 | * |
| 284 | * This function causes the currently running process to exit. The |
| 285 | * function must be called by the process before it unloads itself, or |
| 286 | * the system will crash. |
| 287 | * |
| 288 | */ |
| 289 | /*-----------------------------------------------------------------------------------*/ |
| 290 | void |
| 291 | ek_exit(void) |
| 292 | { |
adamdunkels | d3bccb9 | 2004-08-09 20:36:39 +0000 | [diff] [blame] | 293 | register struct ek_proc *q, *p; |
adamdunkels | 2764255 | 2004-07-04 11:54:10 +0000 | [diff] [blame] | 294 | |
| 295 | p = ek_current; |
| 296 | |
| 297 | /* Post a synchronous event to all processes to inform them that |
| 298 | this process is about to exit. This will allow services to |
| 299 | dealloc state associated with this process. */ |
| 300 | for(q = ek_procs; q != NULL; q = q->next) { |
| 301 | if(p != q) { |
| 302 | ek_current = q; |
| 303 | if(q->eventhandler != NULL) { |
| 304 | q->eventhandler(EK_EVENT_EXITED, (ek_data_t)p->id); |
| 305 | } |
| 306 | } |
| 307 | } |
| 308 | |
| 309 | /* Remove process from the process lists. */ |
| 310 | ek_proclist[p->id] = NULL; |
| 311 | |
| 312 | if(p == ek_procs) { |
| 313 | ek_procs = ek_procs->next; |
| 314 | } else { |
| 315 | for(q = ek_procs; q != NULL; q = q->next) { |
| 316 | if(q->next == p) { |
| 317 | q->next = p->next; |
| 318 | break; |
| 319 | } |
| 320 | } |
| 321 | } |
adamdunkels | 2764255 | 2004-07-04 11:54:10 +0000 | [diff] [blame] | 322 | |
| 323 | ek_current = NULL; |
| 324 | } |
| 325 | /** |
| 326 | * \addtogroup kernel |
| 327 | * @{ |
| 328 | */ |
| 329 | |
| 330 | /*-----------------------------------------------------------------------------------*/ |
| 331 | /** |
| 332 | * Finds the process structure for a specific process ID. |
| 333 | * |
| 334 | * \param id The process ID for the process. |
| 335 | * |
| 336 | * \return The process structure for the process, or NULL if there |
| 337 | * process ID was not found. |
| 338 | */ |
| 339 | /*-----------------------------------------------------------------------------------*/ |
| 340 | struct ek_proc * |
| 341 | ek_process(ek_id_t id) |
| 342 | { |
| 343 | struct ek_proc *p; |
| 344 | for(p = ek_procs; p != NULL; p = p->next) { |
| 345 | if(p->id == id) { |
| 346 | return p; |
| 347 | } |
| 348 | } |
| 349 | return NULL; |
| 350 | } |
| 351 | /*-----------------------------------------------------------------------------------*/ |
| 352 | /** |
| 353 | * Initializes the dispatcher module. |
| 354 | * |
| 355 | * Must be called during the initialization of Contiki. |
| 356 | * |
| 357 | */ |
| 358 | /*-----------------------------------------------------------------------------------*/ |
| 359 | void |
| 360 | ek_init(void) |
| 361 | { |
| 362 | int i; |
| 363 | |
| 364 | lastevent = EK_EVENT_MAX; |
| 365 | |
| 366 | nevents = fevent = 0; |
| 367 | |
adamdunkels | d3bccb9 | 2004-08-09 20:36:39 +0000 | [diff] [blame] | 368 | ek_current = ek_procs = NULL; |
| 369 | |
adamdunkels | 2764255 | 2004-07-04 11:54:10 +0000 | [diff] [blame] | 370 | arg_init(); |
| 371 | |
| 372 | for(i = 0; i < EK_CONF_MAXPROCS; ++i) { |
| 373 | ek_proclist[i] = NULL; |
| 374 | } |
| 375 | } |
| 376 | /*-----------------------------------------------------------------------------------*/ |
| 377 | /** |
| 378 | * Process the next event in the event queue and deliver it to |
| 379 | * listening processes. |
| 380 | * |
| 381 | */ |
| 382 | /*-----------------------------------------------------------------------------------*/ |
| 383 | void |
| 384 | ek_process_event(void) |
| 385 | { |
| 386 | static ek_event_t s; |
| 387 | static ek_data_t data; |
| 388 | static ek_id_t id; |
| 389 | static struct ek_proc *p; |
| 390 | |
| 391 | /* If there are any events in the queue, take the first one and |
| 392 | walk through the list of processes to see if the event should be |
| 393 | delivered to any of them. If so, we call the event handler |
| 394 | function for the process. We only process one event at a time |
| 395 | and call the poll handlers inbetween. */ |
| 396 | |
| 397 | if(nevents > 0) { |
| 398 | |
| 399 | /* There are events that we should deliver. */ |
| 400 | s = events[fevent].s; |
| 401 | |
| 402 | data = events[fevent].data; |
| 403 | id = events[fevent].id; |
| 404 | |
| 405 | /* Since we have seen the new event, we move pointer upwards |
| 406 | and decrese number. */ |
| 407 | fevent = (fevent + 1) % EK_CONF_NUMEVENTS; |
| 408 | --nevents; |
| 409 | |
| 410 | /* If this is a broadcast event, we deliver it to all events, in |
| 411 | order of their priority. */ |
| 412 | if(id == EK_BROADCAST) { |
| 413 | for(p = ek_procs; p != NULL; p = p->next) { |
| 414 | |
| 415 | if(ek_poll_request) { |
| 416 | ek_poll_request = 0; |
| 417 | ek_process_poll(); |
| 418 | } |
| 419 | |
| 420 | ek_current = p; |
| 421 | if(p->eventhandler != NULL) { |
| 422 | p->eventhandler(s, data); |
| 423 | } |
| 424 | } |
| 425 | } else { |
adamdunkels | 442bdc8 | 2005-02-22 22:46:33 +0000 | [diff] [blame] | 426 | /* This is not a broadcast event, so we deliver it to the |
| 427 | specified process. */ |
adamdunkels | 2764255 | 2004-07-04 11:54:10 +0000 | [diff] [blame] | 428 | if(ek_poll_request) { |
| 429 | ek_poll_request = 0; |
| 430 | ek_process_poll(); |
| 431 | } |
adamdunkels | d3bccb9 | 2004-08-09 20:36:39 +0000 | [diff] [blame] | 432 | |
adamdunkels | 2764255 | 2004-07-04 11:54:10 +0000 | [diff] [blame] | 433 | p = ek_proclist[id]; |
| 434 | if(p != NULL && |
| 435 | p->eventhandler != NULL) { |
| 436 | ek_current = p; |
adamdunkels | 442bdc8 | 2005-02-22 22:46:33 +0000 | [diff] [blame] | 437 | p->eventhandler(s, data); |
| 438 | |
| 439 | /* If the event was an INIT event, we should also put the |
| 440 | process on the process list. */ |
| 441 | /* procs_add(p);*/ |
adamdunkels | 2764255 | 2004-07-04 11:54:10 +0000 | [diff] [blame] | 442 | } |
| 443 | } |
| 444 | } |
| 445 | |
| 446 | } |
| 447 | /*-----------------------------------------------------------------------------------*/ |
| 448 | /** |
| 449 | * Call each process' poll handler. |
| 450 | */ |
| 451 | /*-----------------------------------------------------------------------------------*/ |
| 452 | void |
| 453 | ek_process_poll(void) |
| 454 | { |
| 455 | struct ek_proc *p; |
| 456 | |
| 457 | /* Call poll handlers. */ |
| 458 | for(p = ek_procs; p != NULL; p = p->next) { |
adamdunkels | 5acd9ef | 2004-09-01 18:19:43 +0000 | [diff] [blame] | 459 | if(ek_poll_request) { |
| 460 | ek_poll_request = 0; |
| 461 | p = ek_procs; |
| 462 | } |
| 463 | |
adamdunkels | 2764255 | 2004-07-04 11:54:10 +0000 | [diff] [blame] | 464 | if(p->pollhandler != NULL) { |
| 465 | ek_current = p; |
| 466 | p->pollhandler(); |
| 467 | } |
| 468 | } |
| 469 | |
| 470 | } |
| 471 | /*-----------------------------------------------------------------------------------*/ |
| 472 | /** |
| 473 | * Run the system once - call poll handlers and process one event. |
| 474 | * |
| 475 | * This function should be called repeatedly from the main() program |
| 476 | * to actuall run the Contiki system. It calls the necessary poll |
| 477 | * handlers, and processes one event. The function returns the number |
| 478 | * of events that are waiting in the event queue so that the caller |
| 479 | * may choose to put the CPU to sleep when there are no pending |
| 480 | * events. |
| 481 | * |
| 482 | * \return The number of events that are currently waiting in the |
| 483 | * event queue. |
| 484 | */ |
| 485 | /*-----------------------------------------------------------------------------------*/ |
| 486 | int |
| 487 | ek_run(void) |
| 488 | { |
| 489 | /* Process "poll" events. */ |
adamdunkels | 5acd9ef | 2004-09-01 18:19:43 +0000 | [diff] [blame] | 490 | do { |
| 491 | ek_poll_request = 0; |
| 492 | ek_process_poll(); |
| 493 | } while(ek_poll_request != 0); |
adamdunkels | 2764255 | 2004-07-04 11:54:10 +0000 | [diff] [blame] | 494 | |
| 495 | /* Process one event */ |
| 496 | ek_process_event(); |
| 497 | |
| 498 | return nevents; |
| 499 | } |
| 500 | /*-----------------------------------------------------------------------------------*/ |
| 501 | /** |
| 502 | * Post an asynchronous event. |
| 503 | * |
| 504 | * This function posts an asynchronous event to one or more |
| 505 | * processes. The handing of the event is deferred until the target |
| 506 | * process is scheduled by the kernel. An event can be broadcast to |
| 507 | * all processes, in which case all processes in the system will be |
| 508 | * scheduled to handle the event. |
| 509 | * |
| 510 | * \param s The event to be posted. |
| 511 | * |
| 512 | * \param data The auxillary data to be sent with the event |
| 513 | * |
| 514 | * \param id The process ID to which the event should be posted, or |
| 515 | * EK_BROADCAST if the event should be posted to all |
| 516 | * processes. |
| 517 | * |
| 518 | * \retval EK_ERR_OK The event could be posted. |
| 519 | * |
| 520 | * \retval EK_ERR_FULL The event queue was full and the event could |
| 521 | * not be posted. |
| 522 | */ |
| 523 | /*-----------------------------------------------------------------------------------*/ |
| 524 | ek_err_t |
| 525 | ek_post(ek_id_t id, ek_event_t s, ek_data_t data) |
| 526 | { |
| 527 | static unsigned char snum; |
| 528 | |
| 529 | if(nevents == EK_CONF_NUMEVENTS) { |
| 530 | return EK_ERR_FULL; |
| 531 | } |
| 532 | |
| 533 | snum = (fevent + nevents) % EK_CONF_NUMEVENTS; |
| 534 | events[snum].s = s; |
| 535 | events[snum].data = data; |
| 536 | events[snum].id = id; |
| 537 | ++nevents; |
| 538 | |
| 539 | return EK_ERR_OK; |
| 540 | } |
| 541 | /*-----------------------------------------------------------------------------------*/ |
| 542 | void |
| 543 | ek_post_synch(ek_id_t id, ek_event_t ev, ek_data_t data) |
| 544 | { |
adamdunkels | d3bccb9 | 2004-08-09 20:36:39 +0000 | [diff] [blame] | 545 | struct ek_proc *p = ek_current; |
| 546 | |
adamdunkels | 2764255 | 2004-07-04 11:54:10 +0000 | [diff] [blame] | 547 | ek_current = ek_proclist[id]; |
| 548 | ek_current->eventhandler(ev, data); |
| 549 | ek_current = p; |
| 550 | } |
| 551 | /*-----------------------------------------------------------------------------------*/ |
| 552 | ek_id_t |
| 553 | ek_find(const char *prefix) |
| 554 | { |
| 555 | struct ek_proc *p; |
| 556 | unsigned short len; |
| 557 | |
| 558 | /* Search through all processes and search for the specified process |
| 559 | name. */ |
| 560 | len = strlen(prefix); |
| 561 | for(p = ek_procs; p != NULL; p = p->next) { |
| 562 | if(strncmp(prefix, p->name, len) == 0) { |
| 563 | return p->id; |
| 564 | } |
| 565 | } |
| 566 | |
| 567 | return EK_ID_NONE; |
| 568 | } |
| 569 | /*-----------------------------------------------------------------------------------*/ |
| 570 | void |
| 571 | ek_replace(struct ek_proc *newp, void *arg) |
| 572 | { |
adamdunkels | d3bccb9 | 2004-08-09 20:36:39 +0000 | [diff] [blame] | 573 | register struct ek_proc *p = ek_current; |
| 574 | |
adamdunkels | 2764255 | 2004-07-04 11:54:10 +0000 | [diff] [blame] | 575 | /* Remove the currently executing process. */ |
| 576 | ek_exit(); |
| 577 | |
| 578 | ek_proclist[p->id] = newp; |
| 579 | |
| 580 | /* Put on the procs list.*/ |
| 581 | procs_add(newp); |
| 582 | |
| 583 | newp->id = p->id; |
| 584 | |
| 585 | /* Post an asynchronous event to the process. */ |
adamdunkels | d3bccb9 | 2004-08-09 20:36:39 +0000 | [diff] [blame] | 586 | ek_post(p->id, EK_EVENT_REPLACE, arg); |
adamdunkels | 2764255 | 2004-07-04 11:54:10 +0000 | [diff] [blame] | 587 | } |
| 588 | /*-----------------------------------------------------------------------------------*/ |
| 589 | void * |
| 590 | ek_procstate(ek_id_t id) |
| 591 | { |
| 592 | struct ek_proc *p; |
| 593 | |
| 594 | p = ek_proclist[id]; |
| 595 | if(p == NULL) { |
| 596 | return NULL; |
| 597 | } |
| 598 | return p->procstate; |
| 599 | } |
| 600 | /*-----------------------------------------------------------------------------------*/ |
| 601 | /** @} */ |