Zephyr poll
Posted 咕咚.萌西
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Zephyr poll相关的知识,希望对你有一定的参考价值。
文章目录
简介
- 在Zephyr中,polling是一种等待事件的机制,它可以等待多个事件同时发生。
- 在Zephyr中,可以使用k_poll()函数来等待事件。k_poll()函数接受一个k_poll_event数组,数组中的每个元素都描述了一个等待的事件。
- 在等待期间,线程会被阻塞,直到所有事件都发生或等待超时。
- 在等待结束后,k_poll()函数会返回一个整数,表示发生的事件数。
- poll 中除了提供等待机制,还存在一种轻量级的同步对象 k_poll_signal,与队列,fifo,这些同步通信方式类型,但是它比较简单,只能向等待线程发送一个信号被触发的通知,再加上一个返回值,除此之外没有其他的功能。
struct k_poll_event
struct k_poll_event
/* _node 第一个成员,确保内存 k_poll_event 与双链表节点对齐,
* 可以将 k_poll_event 插入到双链表中,当等待的事件还未发生时,
* 调用 k_poll 的线程会将 k_poll_event 插入到目标对象中的 poll_events 双链表中,
* 当目标对象发生指定事件时,IPC 对象会从 poll_events 取出节点并唤醒线程
*/
sys_dnode_t _node;
/* poller 不需要创建,它指向需要等待的线程中的 poller,
* poller 代表的是线程的等待方式,调用 k_poll 函数时会自动设置对应的模式,
* 同时将 k_poll_event 中的 poller 进行初始化(指向当前线程),
* 除此之外 poller 还有一个额外的功能,此处 poller 记录的是线程中 poller 变量的地址,
* 线程中 poller 变量相对于其 tcb 首地址的偏移是固定的,
* 通过 poller 地址减去偏移可以获得对应线程 tcb
*/
struct z_poller *poller;
/* optional user-specified tag, opaque, untouched by the API */
uint32_t tag:8;
/* 等待的事件类型,此处类型需要与下方union中传入的指针类型相对应,
* 否则会出现无法预料的错误
*/
uint32_t type:_POLL_NUM_TYPES;
/* 等待事件的状态,在调用轮询api之前应设置为 K_POLL_STATE_NOT_READY
* 函数调用返回之后通过 state 的值判断对应的事件是否发生,
* 如需再次使用需要重新初始化 state 为 K_POLL_STATE_NOT_READY
*/
uint32_t state:_POLL_NUM_STATES;
/* 轮询线程在可用时不获取对象的所有权 */
uint32_t mode:1;
/* unused bits in 32-bit word */
uint32_t unused:_POLL_EVENT_NUM_UNUSED_BITS;
/* 保存具体对象的地址,用于访问对象中的 poll_events 双链表 */
union
void *obj;
struct k_poll_signal *signal;
struct k_sem *sem;
struct k_fifo *fifo;
struct k_queue *queue;
struct k_msgq *msgq;
#ifdef CONFIG_PIPES
struct k_pipe *pipe;
#endif
;
;
struct k_poll_event 功能
-
struct k_poll_event 可以当作一个双链表节点,里面除了双链表的pre和next指针外,还包含等待的信息,将线程与IPC对象之间联系起来。
-
当事件未发生,线程需要挂起时可以访问 IPC 对象中的 poll_events 链表,将 event 放入链表。
static inline void register_event(struct k_poll_event *event,
struct z_poller *poller)
switch (event->type)
case K_POLL_TYPE_SEM_AVAILABLE:
__ASSERT(event->sem != NULL, "invalid semaphore\\n");
add_event(&event->sem->poll_events, event, poller);
break;
/* ... */
event->poller = poller;
- 当线程调用 k_poll 进行等待时,线程可以获取 IPC 状态判断对应事件是否发生,以决定是否需要继续等待。
static inline bool is_condition_met(struct k_poll_event *event, uint32_t *state)
switch (event->type)
case K_POLL_TYPE_SEM_AVAILABLE:
if (k_sem_count_get(event->sem) > 0U)
*state = K_POLL_STATE_SEM_AVAILABLE;
return true;
break;
/* ... */
return false;
- 当 IPC 对象中发生指定事件时,会从 poll_events 链表中取出 event 节点,设置 event 的状态,然后把等待线程唤醒。
void z_handle_obj_poll_events(sys_dlist_t *events, uint32_t state)
struct k_poll_event *poll_event;
poll_event = (struct k_poll_event *)sys_dlist_get(events);
if (poll_event != NULL)
(void) signal_poll_event(poll_event, state);
static int signal_poll_event(struct k_poll_event *event, uint32_t state)
struct z_poller *poller = event->poller;
int retcode = 0;
if (poller != NULL)
if (poller->mode == MODE_POLL)
/* 将等待的线程设置为就绪态 */
retcode = signal_poller(event, state);
else if (poller->mode == MODE_TRIGGERED)
retcode = signal_triggered_work(event, state);
else
/* Poller is not poll or triggered mode. No action needed.*/
;
poller->is_polling = false;
if (retcode < 0)
return retcode;
/* 设置state */
set_event_ready(event, state);
return retcode;
轮询类型
- 下面是Zephyr中支持的等待类型:
#define K_POLL_TYPE_IGNORE 0
#define K_POLL_TYPE_SIGNAL Z_POLL_TYPE_BIT(_POLL_TYPE_SIGNAL) // 1
#define K_POLL_TYPE_SEM_AVAILABLE Z_POLL_TYPE_BIT(_POLL_TYPE_SEM_AVAILABLE) // 2
#define K_POLL_TYPE_DATA_AVAILABLE Z_POLL_TYPE_BIT(_POLL_TYPE_DATA_AVAILABLE) // 4
#define K_POLL_TYPE_FIFO_DATA_AVAILABLE K_POLL_TYPE_DATA_AVAILABLE // 4
#define K_POLL_TYPE_MSGQ_DATA_AVAILABLE Z_POLL_TYPE_BIT(_POLL_TYPE_MSGQ_DATA_AVAILABLE) // 8
#define K_POLL_TYPE_PIPE_DATA_AVAILABLE Z_POLL_TYPE_BIT(_POLL_TYPE_PIPE_DATA_AVAILABLE) // 16
- Zephyr内核支持等待信号,信号量,队列,FIFO,msgq,管道这几种类型的事件。
- 一般的IPC通信方式虽然会提供等待机制,但是其只能针对一种事件进行等待,而不能等待多个事件(此处的事件特指 IPC 事件),例如我们无法在等待信号量的同时等待队列,或者同时等待多个队列,Zephyr中为我们提供了Polling API,它可以同时等待多个事件到来。
轮询状态
#define K_POLL_STATE_NOT_READY 0
#define K_POLL_STATE_SIGNALED Z_POLL_STATE_BIT(_POLL_STATE_SIGNALED) // 1
#define K_POLL_STATE_SEM_AVAILABLE Z_POLL_STATE_BIT(_POLL_STATE_SEM_AVAILABLE) // 2
#define K_POLL_STATE_DATA_AVAILABLE Z_POLL_STATE_BIT(_POLL_STATE_DATA_AVAILABLE) // 4
#define K_POLL_STATE_FIFO_DATA_AVAILABLE K_POLL_STATE_DATA_AVAILABLE // 4
#define K_POLL_STATE_MSGQ_DATA_AVAILABLE Z_POLL_STATE_BIT(_POLL_STATE_MSGQ_DATA_AVAILABLE)// 16
#define K_POLL_STATE_PIPE_DATA_AVAILABLE Z_POLL_STATE_BIT(_POLL_STATE_PIPE_DATA_AVAILABLE)// 32
#define K_POLL_STATE_CANCELLED Z_POLL_STATE_BIT(_POLL_STATE_CANCELLED) // 8
- 在调用k_poll之前需将状态设置为 K_POLL_STATE_NOT_READY,避免调用返回后读取到错误的状态。
- 每个状态与轮询的类型一一对应,除此之外,如果在等待过程中其他线程调用了取消等待的函数,被等待的线程会被唤醒并返回一错误码。
初始化
#define K_POLL_EVENT_INITIALIZER(_event_type, _event_mode, _event_obj) \\
\\
.poller = NULL, \\
.type = _event_type, \\
.state = K_POLL_STATE_NOT_READY, \\
.mode = _event_mode, \\
.unused = 0, \\
\\
.obj = _event_obj, \\
, \\
#define K_POLL_EVENT_STATIC_INITIALIZER(_event_type, _event_mode, _event_obj, \\
event_tag) \\
\\
.tag = event_tag, \\
.type = _event_type, \\
.state = K_POLL_STATE_NOT_READY, \\
.mode = _event_mode, \\
.unused = 0, \\
\\
.obj = _event_obj, \\
, \\
- 在Zephyr中提供了两个宏用于静态初始化。
- _event_type 代表等待的事件类型。
- _event_mode 固定为 K_POLL_MODE_NOTIFY_ONLY。
- _event_obj 代表目标对象地址,可以是struct k_poll_signal、struct k_sem、struct k_fifo、struct k_queue、struct k_msgq、struct k_pipe类型的变量,传入的对象需与等待的类型一致。
void k_poll_event_init(struct k_poll_event *event, uint32_t type, int mode, void *obj);
- 除了使用宏在定义变量时进行初始化之外,还可以使用 k_poll_event_init 进行初始化,它的功能和上面的两个宏功能一样,函数可以直接传入变量地址后即可初始化,而上面两个宏只能在变量定义时初始化,当执行完一次 k_poll 之后需要再次使用时,需要将 k_poll_event 中的 state 重设为 K_POLL_STATE_NOT_READY。
struct k_poll_event events[2] =
K_POLL_EVENT_STATIC_INITIALIZER(K_POLL_TYPE_SEM_AVAILABLE,
K_POLL_MODE_NOTIFY_ONLY,
&my_sem, 0),
K_POLL_EVENT_STATIC_INITIALIZER(K_POLL_TYPE_FIFO_DATA_AVAILABLE,
K_POLL_MODE_NOTIFY_ONLY,
&my_fifo, 0),
;
struct k_poll_event events[2];
void some_init(void)
k_poll_event_init(&events[0],
K_POLL_TYPE_SEM_AVAILABLE,
K_POLL_MODE_NOTIFY_ONLY,
&my_sem);
k_poll_event_init(&events[1],
K_POLL_TYPE_FIFO_DATA_AVAILABLE,
K_POLL_MODE_NOTIFY_ONLY,
&my_fifo);
事件等待
- k_poll 在 poll 整个过程中最重要的函数之一,用于等待事件发生。
int z_impl_k_poll(struct k_poll_event *events, int num_events,
k_timeout_t timeout)
int events_registered;
k_spinlock_key_t key;
struct z_poller *poller = &_current->poller;
poller->is_polling = true;
poller->mode = MODE_POLL;
__ASSERT(!arch_is_in_isr(), "");
__ASSERT(events != NULL, "NULL events\\n");
__ASSERT(num_events >= 0, "<0 events\\n");
SYS_PORT_TRACING_FUNC_ENTER(k_poll_api, poll, events);
/* register_events 首先会轮询 events 中的IPC对象,等待的事件是否已经发生,如果已经发生会将 poller->is_polling 设为 false,
* 如果等待的事件没有发生则会将 event 添加到对应的 IPC 对象中的 poll_events 链表中, 等待事件来临并唤醒被挂起的线程
*/
events_registered = register_events(events, num_events, poller,
K_TIMEOUT_EQ(timeout, K_NO_WAIT));
key = k_spin_lock(&lock);
/* 如果poller->is_polling为false,说明已经有事件发生,就不需要再等待了 */
if (!poller->is_polling)
/* 从queue、sem、msgq、pipe等中移除事件 */
clear_event_registrations(events, events_registered, key);
k_spin_unlock(&lock, key);
SYS_PORT_TRACING_FUNC_EXIT(k_poll_api, poll, events, 0);
return 0;
poller->is_polling = false;
/* 如果等待的事件没有发生,timeout等于K_NO_WAIT,就不需要等待了,返回-EAGAIN (超时)*/
if (K_TIMEOUT_EQ(timeout, K_NO_WAIT))
k_spin_unlock(&lock, key);
SYS_PORT_TRACING_FUNC_EXIT(k_poll_api, poll, events, -EAGAIN);
return -EAGAIN;
static _wait_q_t wait_q = Z_WAIT_Q_INIT(&wait_q);
// 如果等待的事件没有发生,timeout不等于K_NO_WAIT,就需要等待,调用z_pend_curr()等待
int swap_rc = z_pend_curr(&lock, key, &wait_q, timeout);
// 从queue、sem、msgq、pipe等中移除事件
key = k_spin_lock(&lock);
clear_event_registrations(events, events_registered, key);
k_spin_unlock(&lock, key);
SYS_PORT_TRACING_FUNC_EXIT(k_poll_api, poll, events, swap_rc);
// swap_rc 为0,说明等待的事件发生了,否则等待超时或者等待被中断
return swap_rc;
static inline int register_events(struct k_poll_event *events,
int num_events,
struct z_poller *poller,
bool just_check)
int events_registered = 0;
for (int ii = 0; ii < num_events; ii++)
k_spinlock_key_t key;
uint32_t state;
key = k_spin_lock(&lock);
/* K_POLL_EVENT_INITIALIZER 会将 obj 进行初始化,而obj等价于queue、sem、msgq、pipe,
当queue、sem、msgq、pipe中不为空时,代表等待的事件已经发生,此时就会调用is_condition_met(),
*/
if (is_condition_met(&events[ii], &state))
/* set_event_ready 会设置初始状态并将 k_poll_event 中的poller设置为NULL */
set_event_ready(&events[ii], state);
poller->is_polling = false;
/* 如果等待的事件没有发生,就会调用register_event(),将事件添加到queue、sem、msgq、pipe等中,
当等待的事件发生时,IPC 对象调用 z_handle_obj_poll_events(),将事件从queue、sem、msgq、pipe等中移除,
从而唤醒等待的线程
*/
else if (!just_check && poller->is_polling)
register_event(&events[ii], poller);
events_registered += 1;
else
/* Event is not one of those identified in is_condition_met()
* catching non-polling events, or is marked for just check,
* or not marked for polling. No action needed.
*/
;
k_spin_unlock(&lock, key);
return events_registered;
事件处理
- 在Zephyr中,IPC 对象发生指定事件时,会将 poll_events 链表中等待的线程进行唤醒,以 queue 为例子,向 queue 插入数据时,会发生 K_POLL_TYPE_DATA_AVAILABLE 类型的事件,而在 queue 的 poll_events 链表中,存放的都是等待该事件而被挂起的线程,当发生该事件时会调用 z_handle_obj_poll_events 从其中取出一个节点,唤醒对应线程。
void z_handle_obj_poll_events(sys_dlist_t *events, uint32_t state)
struct k_poll_event *poll_event;
/* 等待事件的线程会被放入到IPC对象的 poll_events 链表中,这里从链表中取出事件,
* 然后调用signal_poll_event()函数处理事件
*/
poll_event = (struct k_poll_event *)sys_dlist_get(events);
if (poll_event != NULL)
(void) signal_poll_event(poll_event, state);
- signal_poll_event 中会调用 signal_poller,最终将唤醒等待线程。
static int signal_poll_event(struct k_poll_event *event, uint32_t state)
struct z_poller *poller = event->poller;
int retcode = 0;
/* k_poll_event 中的pooller可以根据mode的不同,进行不同处理 */
if (poller != NULL)
if (poller->mode == MODE_POLL)
retcode = signal_poller(event, state);
else if (poller->mode == MODE_TRIGGERED)
retcode = signal_triggered_work(event, state);
else
/* Poller is not poll or triggered mode. No action needed.*/
;
poller->is_polling = false;
if (retcode < 0)
return retcode;
/* 修改对应事件的状态为就绪态 */
set_event_ready(event, state);
return retcode;
static int signal_poller(struct k_poll_event *event, uint32_t state)
struct k_thread *thread = poller_thread(event->poller);
__ASSERT(thread != NULL, "poller should have a thread\\n");
// 如果线程不再等待,直接返回0
if (!z_is_thread_pending(thread))
return 0;
// 如果线程处于等待超时状态,直接返回-EAGAIN
if (z_is_thread_timeout_expired(thread))
return -EAGAIN;
// 将线程从等待队列中移除
z_unpend_thread(thread);
// 设置线程的返回值,如果state == K_POLL_STATE_CANCELLED,返回-EINTR,否则返回0
arch_thread_return_value_set(thread,
state == K_POLL_STATE_CANCELLED ? -EINTR : 0);
if (!z_is_thread_ready(thread))
return 0;
// 将线程添加到就绪队列中
z_ready_thread(thread);
return 0;
struct k_poll_signal
- 在上述轮询类型中其中一种是 K_POLL_TYPE_SIGNAL,是一个“直接”由信号通知的轮询事件,可以看作是一个轻量级的二进制信号量,只有一个线程可以等待。
初始化
- 轮询信号是一个类型为 struct k_poll_signal 的单独对象,类似于信号量或 FIFO,必须附加到 k_poll_event 上,它必须首先通过 K_POLL_SIGNAL_INITIALIZER宏 或者 k_poll_signal_init 函数进行初始化。
struct k_poll_signal signal;
void do_stuff(void)
k_poll_signal_init(&signal);
发出信号和等待信号
- 它通过 k_poll_signal_raise 发出信号,这个函数可以携带一个 result 参数,可以用来向等待的线程传递额外的信息,该参数对于API而言是不透明的,如果是在一个循环中使用k_poll,在每次使用之后应将 k_poll_signal 中的 signaled 设置为0, 同时将 k_poll_event 中的 state 重设为 K_POLL_STATE_NOT_READY。
struct k_poll_signal signal;
void thread_a(void)
k_poll_signal_init(&signal);
struct k_poll_event events[1] =
K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_SIGNAL,
K_POLL_MODE_NOTIFY_ONLY,
&signal),
;
for (;;)
k_poll(events, 1, K_FOREVER);
if (events[0].signal->result == 0xffffffff)
// A-OK!
else
// weird error
events[0].signal->signaled = 0;
events[0].state Zephyr RTOS -- Polling API
文章目录
本笔记基于 Zephyr 版本 2.6.0-rc2
前言
本人正在学习 Zephyr,一个可移植性较强,可以兼容多种开发板及物联网设备的操作系统,如果你感兴趣,可以点此查看我的 学习笔记总述 进行了解!
Polling API - (轮询 API)
轮询 API 用于并发地等待多个条件中的任何一个被满足。
1. Concepts - (概念)
轮询 API 的主要函数是 k_poll()
,它在概念上与 POSIX poll()
函数非常相似,不同之处在于它是对内核对象操作,而不是文件描述符进行操作。
轮询 API 允许单个线程并发地等待一个或多个条件被满足,而不需要单独地主动查看每个条件。
这里有一组有限的条件:
- 信号量可用
- 内核 FIFO 包含准备检索的数据
- 一个轮询信号被发出
想要等待多个条件的线程必须定义一个 轮询事件(poll events) 数组, 每个条件一个。
必须先初始化数组中的所有事件,然后才能轮询数组。
每个事件必须指定必须满足哪种 类型(type) 的条件,以便将其状态更改为表示已满足所请求的条件。
每个事件必须指定它希望满足条件的 内核对象(kernel object)。
每个事件必须指定在满足条件时使用哪种操作 模式(mode)。
每个事件可以选择指定一个 标记(tag) 来将多个事件组合在一起,这是由用户决定的。
除了内核对象之外,还有一个 轮询信号(poll signal) 伪对象类型可以直接发出信号。
k_poll()
函数一旦满足它所等待的条件之一就返回。如果在调用 k_poll()
之前完成,或者由于内核的优先多线程特性,在 k_poll()
返回时可能会有多个完成。调用者必须查看数组中所有轮询事件的状态,以确定完成了哪些事件以及采取哪些操作。
目前,只有一种操作模式可用:不获取对象。例如,这意味着当 k_poll()
返回并且 poll 事件表明信号量可用时, k_poll()
的调用者必须调用 k_sem_take()
以获取信号量的所有权。如果信号量被争用,则不能保证它在 k_sem_give()
被调用时仍然可用。
2. Implementation - (实现)
2.1 Using k_poll()
主要 API 是 k_poll()
,它对类型为 k_poll_event
的轮询事件数组进行操作 。数组中的每个条目都代表一个事件,调用 k_poll()
将等待其条件得到满足。
它们可以使用运行时初始化器 K_POLL_EVENT_INITIALIZER()
或 k_poll_event_init()
或静态初始化器 K_POLL_EVENT_STATIC_INITIALIZER()
进行初始化。必须将与指定 类型 匹配的对象传递给初始值设定项。该 模式 必须设置为 K_POLL_MODE_NOTIFY_ONLY
。状态必须设置为 K_POLL_STATE_NOT_READY
(由初始化者负责)。
用户 标记 是可选的,并且对 API 完全不透明:它的存在是为了帮助用户将类似的事件分组在一起。由于是可选的,它被传递给静态初始化器,而不是运行时初始化器,这是出于性能原因。如果使用运行时初始化器,用户必须在k_poll_event
数据结构中单独设置它。如果要忽略数组中的事件(很可能是暂时的),可以将其类型设置为 K_POLL_TYPE_IGNORE
。
struct k_poll_event events[2] = {
K_POLL_EVENT_STATIC_INITIALIZER(K_POLL_TYPE_SEM_AVAILABLE,
K_POLL_MODE_NOTIFY_ONLY,
&my_sem, 0),
K_POLL_EVENT_STATIC_INITIALIZER(K_POLL_TYPE_FIFO_DATA_AVAILABLE,
K_POLL_MODE_NOTIFY_ONLY,
&my_fifo, 0),
};
或在运行时
struct k_poll_event events[2];
void some_init(void)
{
k_poll_event_init(&events[0],
K_POLL_TYPE_SEM_AVAILABLE,
K_POLL_MODE_NOTIFY_ONLY,
&my_sem);
k_poll_event_init(&events[1],
K_POLL_TYPE_FIFO_DATA_AVAILABLE,
K_POLL_MODE_NOTIFY_ONLY,
&my_fifo);
// tags are left uninitialized if unused
}
初始化事件后,可以将数组传递给 k_poll()
。可以将超时指定为只等待指定数量的时间,或者将特殊值 K_NO_WAIT
和 K_FOREVER
指定为不等待或等待事件条件得到满足。
每个信号量或 FIFO 上都提供了一个轮询器列表,并且可以根据应用程序的需要在其中等待尽可能多的事件。请注意,等待者将按照 先到先得的顺序 服务,而不是按优先顺序。
如果成功,则 k_poll()
返回 0。如果超时,则返回 -EAGAIN
。
// assume there is no contention on this semaphore and FIFO
// -EADDRINUSE will not occur; the semaphore and/or data will be available
void do_stuff(void)
{
rc = k_poll(events, 2, 1000);
if (rc == 0) {
if (events[0].state == K_POLL_STATE_SEM_AVAILABLE) {
k_sem_take(events[0].sem, 0);
} else if (events[1].state == K_POLL_STATE_FIFO_DATA_AVAILABLE) {
data = k_fifo_get(events[1].fifo, 0);
// handle data
}
} else {
// handle timeout
}
}
当 k_poll()
在循环中调用时,事件状态必须由用户重置为 K_POLL_STATE_NOT_READY
。
void do_stuff(void)
{
for(;;) {
rc = k_poll(events, 2, K_FOREVER);
if (events[0].state == K_POLL_STATE_SEM_AVAILABLE) {
k_sem_take(events[0].sem, 0);
} else if (events[1].state == K_POLL_STATE_FIFO_DATA_AVAILABLE) {
data = k_fifo_get(events[1].fifo, 0);
// handle data
}
events[0].state = K_POLL_STATE_NOT_READY;
events[1].state = K_POLL_STATE_NOT_READY;
}
}
2.2 Using k_poll_signal_raise()
事件类型之一是 K_POLL_TYPE_SIGNAL
:这是轮询事件的 “direct” 信号。这可以看作是一个只有一个线程可以等待的轻量级二进制信号量。
轮询信号是 k_poll_signal
类型的单独对象,必须附加到 k_poll_event,类似于信号量或 FIFO。它必须首先通过 K_POLL_SIGNAL_INITIALIZER()
或 k_poll_signal_init()
进行初始化。
struct k_poll_signal signal;
void do_stuff(void)
{
k_poll_signal_init(&signal);
}
它是通过 k_poll_signal_raise()
函数来通知的。该函数接受一个用户结果参数,该参数对 API 是不透明的,可用于将额外的信息传递给等待事件的线程。
struct k_poll_signal signal;
// thread A
void do_stuff(void)
{
k_poll_signal_init(&signal);
struct k_poll_event events[1] = {
K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_SIGNAL,
K_POLL_MODE_NOTIFY_ONLY,
&signal),
};
k_poll(events, 1, K_FOREVER);
if (events.signal->result == 0x1337) {
// A-OK!
} else {
// weird error
}
}
// thread B
void signal_do_stuff(void)
{
k_poll_signal_raise(&signal, 0x1337);
}
如果信号要在循环中轮询,如果信号已经被轮询,则必须在每次迭代中重置它的事件状态和它的有信号字段。
struct k_poll_signal signal;
void do_stuff(void)
{
k_poll_signal_init(&signal);
struct k_poll_event events[1] = {
K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_SIGNAL,
K_POLL_MODE_NOTIFY_ONLY,
&signal),
};
for (;;) {
k_poll(events, 1, K_FOREVER);
if (events[0].signal->result == 0x1337) {
// A-OK!
} else {
// weird error
}
events[0].signal->signaled = 0;
events[0].state = K_POLL_STATE_NOT_READY;
}
}
3. Suggested Uses - (建议用途)
使用 k_poll()
合并将在一个对象上暂挂的多个线程,从而节省大量堆栈空间。
因为对象只有在没有其他线程等待它们可用时才会发出信号,而且只有一个线程可以轮询特定的对象,所以轮询最好是在对象不是多个线程争用,基本上,当单个线程作为多个对象的主“服务器”或“分派器”运行,并且是唯一试图获取这些对象的线程时的情况下使用。
4. Configuration Options - (配置选项)
相关配置选项:
参考链接
https://docs.zephyrproject.org/latest/reference/kernel/other/polling.html#
以上是关于Zephyr poll的主要内容,如果未能解决你的问题,请参考以下文章