/* * Copyright (c) 2005, Swedish Institute of Computer Science * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This file is part of the Contiki operating system. * * @(#)$Id: process.h,v 1.7 2007/04/02 18:07:26 adamdunkels Exp $ */ /** * \addtogroup sys * @{ */ /** * \defgroup process Contiki processes * * A process in Contiki consists of a single \ref pt "protothread". * * @{ */ /** * \file * Header file for the Contiki process interface. * \author * Adam Dunkels * */ #ifndef __PROCESS_H__ #define __PROCESS_H__ #include "sys/pt.h" #include "sys/cc.h" typedef unsigned char process_event_t; typedef void * process_data_t; typedef unsigned char process_num_events_t; /** * \name Return values * @{ */ /** * \brief Return value indicating that an operation was successful. * * This value is returned to indicate that an operation * was successful. */ #define PROCESS_ERR_OK 0 /** * \brief Return value indicating that the event queue was full. * * This value is returned from process_post() to indicate * that the event queue was full and that an event could * not be posted. */ #define PROCESS_ERR_FULL 1 /* @} */ #define PROCESS_NONE NULL #ifndef PROCESS_CONF_NUMEVENTS #define PROCESS_CONF_NUMEVENTS 32 #endif /* PROCESS_CONF_NUMEVENTS */ #define PROCESS_EVENT_NONE 0x80 #define PROCESS_EVENT_INIT 0x81 #define PROCESS_EVENT_POLL 0x82 #define PROCESS_EVENT_EXIT 0x83 #define PROCESS_EVENT_SERVICE_REMOVED 0x84 #define PROCESS_EVENT_CONTINUE 0x85 #define PROCESS_EVENT_MSG 0x86 #define PROCESS_EVENT_EXITED 0x87 #define PROCESS_EVENT_TIMER 0x88 #define PROCESS_EVENT_COM 0x89 #define PROCESS_EVENT_MAX 0x8a #define PROCESS_BROADCAST NULL #define PROCESS_ZOMBIE ((struct process *)0x1) /** * \name Process protothread functions * @{ */ /** * Define the beginning of a process. * * This macro defines the beginning of a process, and must always * appear in a PROCESS_THREAD() definition. The PROCESS_END() macro * must come at the end of the process. * * \hideinitializer */ #define PROCESS_BEGIN() PT_BEGIN(process_pt) /** * Define the end of a process. * * This macro defines the end of a process. It must appear in a * PROCESS_THREAD() definition and must always be included. The * process exits when the PROCESS_END() macro is reached. * * \hideinitializer */ #define PROCESS_END() PT_END(process_pt) /** * Wait for an event to be posted to the process. * * This macro blocks the currently running process until the process * receives an event. * * \hideinitializer */ #define PROCESS_WAIT_EVENT() PROCESS_YIELD() /** * Wait for an event to be posted to the process, with an extra * condition. * * This macro is similar to PROCESS_WAIT_EVENT() in that it blocks the * currently running process until the process receives an event. But * PROCESS_WAIT_EVENT_UNTIL() takes an extra condition which must be * true for the process to continue. * * \param c The condition that must be true for the process to continue. * \sa PT_WAIT_UNTIL() * * \hideinitializer */ #define PROCESS_WAIT_EVENT_UNTIL(c) PROCESS_YIELD_UNTIL(c) /** * Yield the currently running process. * * \hideinitializer */ #define PROCESS_YIELD() PT_YIELD(process_pt) /** * Yield the currently running process until a condition occurs. * * This macro is different from PROCESS_WAIT_UNTIL() in that * PROCESS_YIELD_UNTIL() is guaranteed to always yield at least * once. This ensures that the process does not end up in an infinite * loop and monopolizing the CPU. * * \param c The condition to wait for. * * \hideinitializer */ #define PROCESS_YIELD_UNTIL(c) PT_YIELD_UNTIL(process_pt, c) /** * Wait for a condition to occur. * * This macro does not guarantee that the process yields, and should * therefore be used with care. In most cases, PROCESS_WAIT_EVENT(), * PROCESS_WAIT_EVENT_UNTIL(), PROCESS_YIELD() or * PROCESS_YIELD_UNTIL() should be used instead. * * \param c The condition to wait for. * * \hideinitializer */ #define PROCESS_WAIT_UNTIL(c) PT_WAIT_UNTIL(process_pt, c) #define PROCESS_WAIT_WHILE(c) PT_WAIT_WHILE(process_pt, c) /** * Exit the currently running process. * * \hideinitializer */ #define PROCESS_EXIT() PT_EXIT(process_pt) /** * Spawn a protothread from the process. * * \param pt The protothread state (struct pt) for the new protothread * \param thread The call to the protothread function. * \sa PT_SPAWN() * * \hideinitializer */ #define PROCESS_PT_SPAWN(pt, thread) PT_SPAWN(process_pt, pt, thread) /** * Yield the process for a short while. * * This macro yields the currently running process for a short while, * thus letting other processes run before the process continues. * * \hideinitializer */ #define PROCESS_PAUSE() do { \ process_post(PROCESS_CURRENT(), PROCESS_EVENT_CONTINUE, NULL); \ PROCESS_WAIT_EVENT(); \ } while(0) /** @} end of protothread functions */ /** * \name Poll and exit handlers * @{ */ /** * Specify an action when a process is polled. * * \note This declaration must come immediately before the * PROCESS_BEGIN() macro. * * \param handler The action to be performed. * * \hideinitializer */ #define PROCESS_POLLHANDLER(handler) if(ev == PROCESS_EVENT_POLL) { handler; } /** * Specify an action when a process exits. * * \note This declaration must come immediately before the * PROCESS_BEGIN() macro. * * \param handler The action to be performed. * * \hideinitializer */ #define PROCESS_EXITHANDLER(handler) if(ev == PROCESS_EVENT_EXIT) { handler; } /** @} */ /** * \name Process declaration and definion * @{ */ /** * Define the body of a process. * * This macro is used to define the body (protothread) of a * process. The process is called whenever an event occurs in the * system, A process always start with the PROCESS_BEGIN() macro and * end with the PROCESS_END() macro. * * \hideinitializer */ #define PROCESS_THREAD(name, ev, data) \ static PT_THREAD(process_thread_##name(struct pt *process_pt, \ process_event_t ev, \ process_data_t data)) #if PROCESS_LOADABLE #define PROCESS_LOAD(name) const struct process *process_load = &name; #else /* PROCESS_LOADABLE */ #define PROCESS_LOAD(name) #endif /* PROCESS_LOADABLE */ CLIF extern const struct process *process_load; /** * Declare the name of a process. * * This macro is typically used in header files to declare the name of * a process that is implemented in the C file. * * \hideinitializer */ #define PROCESS_NAME(name) extern struct process name #define PROCESS_NOLOAD(name, strname) \ PROCESS_THREAD(name, ev, data); \ struct process name = { NULL, strname, \ process_thread_##name }; /** * Declare a process. * * This macro declares a process. The process has two names: the * variable of the process structure, which is used by the C program, * and a human readable string name, which is used when debugging. * * \param name The variable name of the process structure. * \param strname The string repressentation of the process' name. * * \hideinitializer */ #define PROCESS(name, strname) \ PROCESS_NOLOAD(name, strname); \ PROCESS_LOAD(name) /** @} */ struct process { struct process *next; const char *name; PT_THREAD((* thread)(struct pt *, process_event_t, process_data_t)); struct pt pt; unsigned char state; }; /** * \name Functions called from application programs * @{ */ /** * Start a process. * * \param p A pointer to a process structure. * * \param arg An argument pointer that can be passed to the new * process * */ void process_start(struct process *p, char *arg); /** * Post an asynchronous event. * * This function posts an asynchronous event to one or more * processes. The handing of the event is deferred until the target * process is scheduled by the kernel. An event can be broadcast to * all processes, in which case all processes in the system will be * scheduled to handle the event. * * \param ev The event to be posted. * * \param data The auxillary data to be sent with the event * * \param p The process to which the event should be posted, or * PROCESS_BROADCAST if the event should be posted to all processes. * * \retval PROCESS_ERR_OK The event could be posted. * * \retval PROCESS_ERR_FULL The event queue was full and the event could * not be posted. */ CCIF int process_post(struct process *p, process_event_t ev, process_data_t data); /** * Post a synchronous event to a process. * * \param p A pointer to the process' process structure. * * \param ev The event to be posted. * * \param data A pointer to additional data that is posted together * with the event. */ void process_post_synch(struct process *p, process_event_t ev, process_data_t data); /** * \brief Cause a process to exit * \param p The process that is to be exited * * This function causes a process to exit. The process can * either be the currently executing process, or another * process that is currently running. * * \sa PROCESS_CURRENT() */ CCIF void process_exit(struct process *p); /** * Get a pointer to the currently running process. * * This macro get a pointer to the currently running * process. Typically, this macro is used to post an event to the * current process with process_post(). * * \hideinitializer */ #define PROCESS_CURRENT() process_current CCIF extern struct process *process_current; #define PROCESS_SET_FLAGS(flags) #define PROCESS_NO_BROADCAST /** * Switch context to another process * * This function switch context to the specified process and executes * the code as if run by that process. Typical use of this function is * to switch context in services, called by other processes. Each * PROCESS_CONTEXT_BEGIN() must be followed by the * PROCESS_CONTEXT_END() macro to end the context switch. * * Example: \code PROCESS_CONTEXT_BEGIN(&test_process); etimer_set(&timer, CLOCK_SECOND); PROCESS_CONTEXT_END(&test_process); \endcode * * \param p The process to use as context * * \sa PROCESS_CONTEXT_END() * \sa PROCESS_CURRENT() */ #define PROCESS_CONTEXT_BEGIN(p) {\ struct process *tmp_current = PROCESS_CURRENT();\ process_current = p /** * End a context switch * * This function ends a context switch and changes back to the * previous process. * * \param p The process used in the context switch * * \sa PROCESS_CONTEXT_START() */ #define PROCESS_CONTEXT_END(p) process_current = tmp_current; } /** * \brief Allocate a global event number. * \return The allocated event number * * In Contiki, event numbers above 128 are global and may * be posted from one process to another. This function * allocates one such event number. * * \note There currently is no way to deallocate an allocated event * number. */ process_event_t process_alloc_event(void); /** @} */ /** * \name Functions called from device drivers * @{ */ /** * Request a process to be polled. * * This function typically is called from an interrupt handler to * cause a process to be polled. * * \param p A pointer to the process' process structure. */ CCIF void process_poll(struct process *p); /** @} */ /** * \name Functions called by the system and boot-up code * @{ */ /** * \brief Initialize the process module. * * This function initializes the process module and should * be called by the system boot-up code. */ void process_init(void); /** * Run the system once - call poll handlers and process one event. * * This function should be called repeatedly from the main() program * to actually run the Contiki system. It calls the necessary poll * handlers, and processes one event. The function returns the number * of events that are waiting in the event queue so that the caller * may choose to put the CPU to sleep when there are no pending * events. * * \return The number of events that are currently waiting in the * event queue. */ int process_run(void); /** * Number of events waiting to be processed. * * \return The number of events that are currently waiting to be * processed. */ int process_nevents(void); /** @} */ CCIF extern struct process *process_list; #define PROCESS_LIST() process_list #endif /* __PROCESS_H__ */ /** @} */ /** @} */