【Contiki】Contiki process概述

00. 目录

文章目录

    • 00. 目录
    • 01. 进程类型
    • 02. 进程结构
    • 03. 事件
    • 04. 进程调度函数
    • 05. 程序实例
    • 06. process实现
    • 07. 附录

01. 进程类型

在这里插入图片描述

进程类型主要有**协同式(cooperative)抢占式(preemptive)**两种。

协同式进程,要等其他进程运行完进程实体函数(进程不一定运行完,这个时候有可能是阻塞,总之只要执行到return语句,具体看),然后才能开始运行。

抢占式进程,会优先运行,当有抢占式进程需要执行时,协同式进程将会被挂起,直到抢占式进程实体函数执行完毕。中断和实时任务就需要用抢占式进程实现。

02. 进程结构

2.1 进程结构体

struct process {struct process *next;//指向下个进程结构体,在进程链表中使用
#if PROCESS_CONF_NO_PROCESS_NAMES//配置进程字符串名字?
#define PROCESS_NAME_STRING(process) ""//没有,空
#else//有字符串名字const char *name;//定义进程字符串名字
#define PROCESS_NAME_STRING(process) (process)->name//取名字
#endifPT_THREAD((* thread)(struct pt *, process_event_t, process_data_t));//进程执行实体函数struct pt pt;//pt结构体,存储实体函数阻塞时的位置unsigned char state, needspoll;//state是进程状态,needspoll标志进程是否需要优先执行
};

2.2 进程链表

process_list ----->
在这里插入图片描述

只要抓住了进程链表头process_list,那么进程的各种操作都做得到了。

2.3 进程执行实体函数

PROCESS_THREAD(hello_world_process, ev, data)
{PROCESS_BEGIN();printf("Hello, world\n");PROCESS_END();
}#define PROCESS_THREAD(name, ev, data)                 \
static PT_THREAD(process_thread_##name(struct pt *process_pt,    \process_event_t ev,    \process_data_t data))#define PT_THREAD(name_args) char name_args

最后展开为

static char process_thread_hello_world_process(struct pt *process_pt, process_event_t ev, process_data_t data)
{//略  
}

03. 事件

非同步事件

在这里插入图片描述

非同步事件处理中,先将事件放到事件队列中,然后事件处理程序再把事件传递给接收这个事件的进程。

同步事件

在这里插入图片描述

同步事件处理中,事件立马就传递给了特定的进程,表现为立马执行ProcessB的执行实体函数。

Polling(推举)

推举某个进程,让这个进程尽可能快的执行。抢占式进程的唯一调用方式。

04. 进程调度函数

先处理所有poll的进程,再处理一个事件,最后返回剩余的事件数。

int
process_run(void)
{/* Process poll events. */if(poll_requested) {do_poll();}/* Process one event from the queue */do_event();return nevents + poll_requested;
}

源码文件

源码: c o n t i k i contiki contiki\core\sys\process.c

源码: c o n t i k i contiki contiki\core\sys\process.h

05. 程序实例

test.c

 #include "contiki.h"PROCESS(example_process, "Example process");AUTOSTART_PROCESSES(&example_process);PROCESS_THREAD(example_process, ev, data){PROCESS_BEGIN();while(1) {PROCESS_WAIT_EVENT();printf("Got event number %d\n", ev);}PROCESS_END();}

06. process实现

process.h

/** 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.**//*** \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 <adam@sics.se>**/
#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_UNTIL(ev == PROCESS_EVENT_CONTINUE);               \
} 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 definition* @{*//*** 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))/*** 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/*** 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.* A configuration option allows removal of the readable name to save RAM.** \param name The variable name of the process structure.* \param strname The string representation of the process' name.** \hideinitializer*/
#if PROCESS_CONF_NO_PROCESS_NAMES
#define PROCESS(name, strname)				\PROCESS_THREAD(name, ev, data);			\struct process name = { NULL,		        \process_thread_##name }
#else
#define PROCESS(name, strname)				\PROCESS_THREAD(name, ev, data);			\struct process name = { NULL, strname,		\process_thread_##name }
#endif/** @} */struct process {struct process *next;
#if PROCESS_CONF_NO_PROCESS_NAMES
#define PROCESS_NAME_STRING(process) ""
#elseconst char *name;
#define PROCESS_NAME_STRING(process) (process)->name
#endifPT_THREAD((* thread)(struct pt *, process_event_t, process_data_t));struct pt pt;unsigned char state, needspoll;
};/*** \name Functions called from application programs* @{*//*** Start a process.** \param p A pointer to a process structure.** \param data An argument pointer that can be passed to the new* process**/
CCIF void process_start(struct process *p, process_data_t data);/*** 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 auxiliary 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.*/
CCIF 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;/*** 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:\codePROCESS_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.*/
CCIF 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);/*** Check if a process is running.** This function checks if a specific process is running.** \param p The process.* \retval Non-zero if the process is running.* \retval Zero if the process is not running.*/
CCIF int process_is_running(struct process *p);/***  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_ *//** @} */
/** @} */

process.c

/** 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.**//*** \addtogroup process* @{*//*** \file*         Implementation of the Contiki process kernel.* \author*         Adam Dunkels <adam@sics.se>**/#include <stdio.h>#include "sys/process.h"
#include "sys/arg.h"/** Pointer to the currently running process structure.*/
struct process *process_list = NULL;
struct process *process_current = NULL;static process_event_t lastevent;/** Structure used for keeping the queue of active events.*/
struct event_data {process_event_t ev;process_data_t data;struct process *p;
};static process_num_events_t nevents, fevent;
static struct event_data events[PROCESS_CONF_NUMEVENTS];#if PROCESS_CONF_STATS
process_num_events_t process_maxevents;
#endifstatic volatile unsigned char poll_requested;#define PROCESS_STATE_NONE        0
#define PROCESS_STATE_RUNNING     1
#define PROCESS_STATE_CALLED      2static void call_process(struct process *p, process_event_t ev, process_data_t data);#define DEBUG 0
#if DEBUG
#include <stdio.h>
#define PRINTF(...) printf(__VA_ARGS__)
#else
#define PRINTF(...)
#endif/*---------------------------------------------------------------------------*/
process_event_t
process_alloc_event(void)
{return lastevent++;
}
/*---------------------------------------------------------------------------*/
void
process_start(struct process *p, process_data_t data)
{struct process *q;/* First make sure that we don't try to start a process that isalready running. */for(q = process_list; q != p && q != NULL; q = q->next);/* If we found the process on the process list, we bail out. */if(q == p) {return;}/* Put on the procs list.*/p->next = process_list;process_list = p;p->state = PROCESS_STATE_RUNNING;PT_INIT(&p->pt);PRINTF("process: starting '%s'\n", PROCESS_NAME_STRING(p));/* Post a synchronous initialization event to the process. */process_post_synch(p, PROCESS_EVENT_INIT, data);
}
/*---------------------------------------------------------------------------*/
static void
exit_process(struct process *p, struct process *fromprocess)
{register struct process *q;struct process *old_current = process_current;PRINTF("process: exit_process '%s'\n", PROCESS_NAME_STRING(p));/* Make sure the process is in the process list before we try toexit it. */for(q = process_list; q != p && q != NULL; q = q->next);if(q == NULL) {return;}if(process_is_running(p)) {/* Process was running */p->state = PROCESS_STATE_NONE;/** Post a synchronous event to all processes to inform them that* this process is about to exit. This will allow services to* deallocate state associated with this process.*/for(q = process_list; q != NULL; q = q->next) {if(p != q) {call_process(q, PROCESS_EVENT_EXITED, (process_data_t)p);}}if(p->thread != NULL && p != fromprocess) {/* Post the exit event to the process that is about to exit. */process_current = p;p->thread(&p->pt, PROCESS_EVENT_EXIT, NULL);}}if(p == process_list) {process_list = process_list->next;} else {for(q = process_list; q != NULL; q = q->next) {if(q->next == p) {q->next = p->next;break;}}}process_current = old_current;
}
/*---------------------------------------------------------------------------*/
static void
call_process(struct process *p, process_event_t ev, process_data_t data)
{int ret;#if DEBUGif(p->state == PROCESS_STATE_CALLED) {printf("process: process '%s' called again with event %d\n", PROCESS_NAME_STRING(p), ev);}
#endif /* DEBUG */if((p->state & PROCESS_STATE_RUNNING) &&p->thread != NULL) {PRINTF("process: calling process '%s' with event %d\n", PROCESS_NAME_STRING(p), ev);process_current = p;p->state = PROCESS_STATE_CALLED;ret = p->thread(&p->pt, ev, data);if(ret == PT_EXITED ||ret == PT_ENDED ||ev == PROCESS_EVENT_EXIT) {exit_process(p, p);} else {p->state = PROCESS_STATE_RUNNING;}}
}
/*---------------------------------------------------------------------------*/
void
process_exit(struct process *p)
{exit_process(p, PROCESS_CURRENT());
}
/*---------------------------------------------------------------------------*/
void
process_init(void)
{lastevent = PROCESS_EVENT_MAX;nevents = fevent = 0;
#if PROCESS_CONF_STATSprocess_maxevents = 0;
#endif /* PROCESS_CONF_STATS */process_current = process_list = NULL;
}
/*---------------------------------------------------------------------------*/
/** Call each process' poll handler.*/
/*---------------------------------------------------------------------------*/
static void
do_poll(void)
{struct process *p;poll_requested = 0;/* Call the processes that needs to be polled. */for(p = process_list; p != NULL; p = p->next) {if(p->needspoll) {p->state = PROCESS_STATE_RUNNING;p->needspoll = 0;call_process(p, PROCESS_EVENT_POLL, NULL);}}
}
/*---------------------------------------------------------------------------*/
/** Process the next event in the event queue and deliver it to* listening processes.*/
/*---------------------------------------------------------------------------*/
static void
do_event(void)
{process_event_t ev;process_data_t data;struct process *receiver;struct process *p;/** If there are any events in the queue, take the first one and walk* through the list of processes to see if the event should be* delivered to any of them. If so, we call the event handler* function for the process. We only process one event at a time and* call the poll handlers inbetween.*/if(nevents > 0) {/* There are events that we should deliver. */ev = events[fevent].ev;data = events[fevent].data;receiver = events[fevent].p;/* Since we have seen the new event, we move pointer upwardsand decrease the number of events. */fevent = (fevent + 1) % PROCESS_CONF_NUMEVENTS;--nevents;/* If this is a broadcast event, we deliver it to all events, inorder of their priority. */if(receiver == PROCESS_BROADCAST) {for(p = process_list; p != NULL; p = p->next) {/* If we have been requested to poll a process, we do this inbetween processing the broadcast event. */if(poll_requested) {do_poll();}call_process(p, ev, data);}} else {/* This is not a broadcast event, so we deliver it to thespecified process. *//* If the event was an INIT event, we should also update thestate of the process. */if(ev == PROCESS_EVENT_INIT) {receiver->state = PROCESS_STATE_RUNNING;}/* Make sure that the process actually is running. */call_process(receiver, ev, data);}}
}
/*---------------------------------------------------------------------------*/
int
process_run(void)
{/* Process poll events. */if(poll_requested) {do_poll();}/* Process one event from the queue */do_event();return nevents + poll_requested;
}
/*---------------------------------------------------------------------------*/
int
process_nevents(void)
{return nevents + poll_requested;
}
/*---------------------------------------------------------------------------*/
int
process_post(struct process *p, process_event_t ev, process_data_t data)
{process_num_events_t snum;if(PROCESS_CURRENT() == NULL) {PRINTF("process_post: NULL process posts event %d to process '%s', nevents %d\n",ev,PROCESS_NAME_STRING(p), nevents);} else {PRINTF("process_post: Process '%s' posts event %d to process '%s', nevents %d\n",PROCESS_NAME_STRING(PROCESS_CURRENT()), ev,p == PROCESS_BROADCAST? "<broadcast>": PROCESS_NAME_STRING(p), nevents);}if(nevents == PROCESS_CONF_NUMEVENTS) {
#if DEBUGif(p == PROCESS_BROADCAST) {printf("soft panic: event queue is full when broadcast event %d was posted from %s\n", ev, PROCESS_NAME_STRING(process_current));} else {printf("soft panic: event queue is full when event %d was posted to %s from %s\n", ev, PROCESS_NAME_STRING(p), PROCESS_NAME_STRING(process_current));}
#endif /* DEBUG */return PROCESS_ERR_FULL;}snum = (process_num_events_t)(fevent + nevents) % PROCESS_CONF_NUMEVENTS;events[snum].ev = ev;events[snum].data = data;events[snum].p = p;++nevents;#if PROCESS_CONF_STATSif(nevents > process_maxevents) {process_maxevents = nevents;}
#endif /* PROCESS_CONF_STATS */return PROCESS_ERR_OK;
}
/*---------------------------------------------------------------------------*/
void
process_post_synch(struct process *p, process_event_t ev, process_data_t data)
{struct process *caller = process_current;call_process(p, ev, data);process_current = caller;
}
/*---------------------------------------------------------------------------*/
void
process_poll(struct process *p)
{if(p != NULL) {if(p->state == PROCESS_STATE_RUNNING ||p->state == PROCESS_STATE_CALLED) {p->needspoll = 1;poll_requested = 1;}}
}
/*---------------------------------------------------------------------------*/
int
process_is_running(struct process *p)
{return p->state != PROCESS_STATE_NONE;
}
/*---------------------------------------------------------------------------*/
/** @} */

07. 附录

参考:Contiki 2.6: Contiki processes

参考:Processes · contiki-os/contiki Wiki · GitHub

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/901908.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

哪种电脑更稳定?Mac?Windows?还是云电脑? 实测解密

随着科技的发展进步&#xff0c;电脑已成为当下各类群体的必备产品之一&#xff0c;它的妙用有很多&#xff0c;无论是学生党、打工人还是已经退休的人群或都离不开它的存在。然而&#xff0c;电脑虽好却也差异很大、不同品牌、不同系统、不同配置、不同价位的统统都会有区别。…

华为openEuler操作系统全解析:起源、特性与生态对比

华为openEuler操作系统全解析&#xff1a;起源、特性与生态对比 一、起源与发展历程 openEuler&#xff08;欧拉操作系统&#xff09;是华为于2019年开源的Linux发行版&#xff0c;其前身为华为内部研发的服务器操作系统EulerOS。EulerOS自2010年起逐步发展&#xff0c;支持华…

第 7 期:DDPM 采样提速方案:从 DDPM 到 DDIM

本期关键词:采样加速、DDIM 推导、可控性提升、伪逆过程、代码实战 前情回顾:DDPM 的采样瓶颈 在前几期中,我们构建了一个完整的 DDPM 生成流程。但是你可能已经发现: 生成一张图像太慢了!!! 原因是: DDPM 要在 T 个时间步中一步步地去噪,从 x_T → x_0。而通常 T 至…

chrome中的copy xpath 与copy full xpath的区别

学过测试或者爬虫的&#xff0c;都感觉获取网页元素&#xff0c;使用xpath最方便 但其中有一些细节可能会使你摸不清头脑 比如有时候copy xpath会定位不准确&#xff0c;而使用copy full xpath就可以定位 1、copy xpath&#xff08;相对路径定位&#xff09; 优点&#xff…

学习海康VisionMaster之中线查找

一&#xff1a;进一步学习了 今天学习下VisionMaster中的中线查找&#xff0c;这个就是字面意思&#xff0c;输入两条直线&#xff0c;输出两条直线的中线 二&#xff1a;开始学习 1&#xff1a;什么是中线查找&#xff1f;今天这个比较简单&#xff0c;其实这个模块算是一个几…

深入浅出 Multi-Head Attention:原理 + 例子 + PyTorch 实现

本文带你一步步理解 Transformer 中最核心的模块&#xff1a;多头注意力机制&#xff08;Multi-Head Attention&#xff09;。从原理到实现&#xff0c;配图 举例 PyTorch 代码&#xff0c;一次性说清楚&#xff01; 什么是 Multi-Head Attention&#xff1f; 简单说&#x…

常用 Git 命令详解

Git 是一个强大的版本控制工具&#xff0c;广泛用于软件开发和团队协作中。掌握 Git 命令可以帮助开发者更高效地管理代码版本和项目进度。本文将介绍一些常用的 Git 命令&#xff0c;并提供示例以帮助你更好地理解和应用这些命令。 目录 常用命令 git clonegit stashgit pul…

NO.96十六届蓝桥杯备战|图论基础-多源最短路|Floyd|Clear And Present Danger|灾后重建|无向图的最小环问题(C++)

多源最短路&#xff1a;即图中每对顶点间的最短路径 floyd算法本质是动态规划&#xff0c;⽤来求任意两个结点之间的最短路&#xff0c;也称插点法。通过不断在两点之间加⼊新的点&#xff0c;来更新最短路。 适⽤于任何图&#xff0c;不管有向⽆向&#xff0c;边权正负&…

电流模式控制学习

电流模式控制 电流模式控制&#xff08;CMC&#xff09;是开关电源中广泛使用的一种控制策略&#xff0c;其核心思想是通过内环电流反馈和外环电压反馈共同调节占空比。相比电压模式控制&#xff0c;CMC具有更快的动态响应和更好的稳定性&#xff0c;但也存在一些固有缺点。 …

MATLAB 控制系统设计与仿真 - 36

鲁棒工具箱定义了个新的对象类ureal,可以定义在某个区间内可变的变量。 函数的调用格式为&#xff1a; p ureal(name,nominalvalue) % name为变量名,nominalValue为标称值&#xff0c;默认变化值为/-1 p ureal(name,nominalvalue,PlusMinus,plusminus) p ureal(name,nomin…

LeetCode -- Flora -- edit 2025-04-17

1.最长连续序列 128. 最长连续序列 给定一个未排序的整数数组 nums &#xff0c;找出数字连续的最长序列&#xff08;不要求序列元素在原数组中连续&#xff09;的长度。 请你设计并实现时间复杂度为 O(n) 的算法解决此问题。 示例 1&#xff1a; 输入&#xff1a;nums [1…

Sql刷题日志(day3)

一、笔试 1、min(date_time)&#xff1a;求最早日期 2、mysql中distinct不能与order by 连用&#xff0c;可以用group by去重 二、面试 1、SQL中如何利用replace函数统计给定重复字段在字符串中的出现次数 (length(all_string)-length(all_string,目标字符串,))/length(ta…

解决 Spring Boot 多数据源环境下事务管理器冲突问题(非Neo4j请求标记了 @Transactional 尝试启动Neo4j的事务管理器)

0. 写在前面 到底遇到了什么问题&#xff1f; 简洁版&#xff1a; 在 Oracle 与 Neo4j 共存的多数据源项目中&#xff0c;一个仅涉及 Oracle 操作的请求&#xff0c;却因为 Neo4j 连接失败而报错。根本原因是 Spring 的默认事务管理器错误地指向了 Neo4j&#xff0c;导致不相…

理解和实现RESTful API的最佳实践

理解和实现RESTful API的最佳实践 在当今数字化时代&#xff0c;APIs已成为软件开发的核心组件&#xff0c;而RESTful API以其简洁、灵活和可扩展性成为最流行的API设计风格。本文将深入探讨RESTful API的概念、特点和实施指南&#xff0c;帮助开发者构建高效、可靠的Web服务。…

大语言模型微调技术与实践:从原理到应用

大语言模型微调技术与实践&#xff1a;从原理到应用 摘要&#xff1a;随着大语言模型&#xff08;LLM&#xff09;技术的迅猛发展&#xff0c;预训练语言模型在各种自然语言处理任务中展现出强大的能力。然而&#xff0c;将这些通用的预训练模型直接应用于特定领域或任务时&am…

遨游科普:三防平板除了三防特性?还能实现什么功能?

在工业4.0浪潮席卷全球的今天&#xff0c;电子设备的功能边界正经历着革命性突破。三防平板电脑作为"危、急、特"场景的智能终端代表&#xff0c;其价值早已超越防水、防尘、防摔的基础防护属性。遨游通讯通过系统级技术创新&#xff0c;将三防平板打造为集通信中枢、…

前端实战:基于 Vue 与 QRCode 库实现动态二维码合成与下载功能

在现代 Web 应用开发中&#xff0c;二维码的应用越来越广泛&#xff0c;从电子票务到信息传递&#xff0c;它都扮演着重要角色。本文将分享如何在 Vue 项目中&#xff0c;结合QRCode库实现动态二维码的生成、与背景图合成以及图片下载功能&#xff0c;打造一个完整且实用的二维…

HAL详解

一、直通式HAL 这里使用一个案例来介绍直通式HAL&#xff0c;选择MTK的NFC HIDL 1.0为例&#xff0c;因为比较简单&#xff0c;代码量也比较小&#xff0c;其源码路径&#xff1a;vendor/hardware/interfaces/nfc/1.0/ 1、NFC HAL的定义 1&#xff09;NFC HAL数据类型 通常定…

Vue自定义指令-防抖节流

Vue2版本 // 防抖 // <el-button v-debounce"[reset,click,300]" ></el-button> // <el-button v-debounce"[reset]" ></el-button> Vue.directive(debounce, { inserted: function (el, binding) { let [fn, event "cl…

AI知识补全(十六):A2A - 谷歌开源的agent通信协议是什么?

名人说&#xff1a;一笑出门去&#xff0c;千里落花风。——辛弃疾《水调歌头我饮不须劝》 创作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 上一篇&#xff1a;AI知识补全&#xff08;十五&#xff09;&#xff1a;AI可解…