Zephyr events_zephyr 事件

  • 其中 events 为事件发布后事件对象中 events 成员变量的值,代表当前已经发生的事件。
  • 当线程或者中断向事件对象发布事件时,因为等待事件被挂起的线程可能需要被唤醒,但是这些线程等待的事件并不相同,需要从等待队列 wait_q 中查找出满足唤醒条件的线程,并将这些线程作为节点添加到被唤醒链表中,head即为链表头。
static int event\_walk\_op(struct k\_thread \*thread, void \*data)
{
	unsigned int      wait_condition;
	struct event\_walk\_data \*event_data = data;

	wait_condition = thread->event_options & K_EVENT_WAIT_MASK;

	if (are\_wait\_conditions\_met(thread->events, event_data->events,
				    wait_condition)) {

		/\*
 \* Events create a list of threads to wake up. We do
 \* not want z\_thread\_timeout to wake these threads; they
 \* will be woken up by k\_event\_post\_internal once they
 \* have been processed.
 \*/
		thread->no_wake_on_timeout = true;

		/\*
 \* The wait conditions have been satisfied. Add this
 \* thread to the list of threads to unpend.
 \*/
		thread->next_event_link = event_data->head;
		event_data->head = thread;
		z\_abort\_timeout(&thread->base.timeout);
	}

	return 0;
}

  • 程序依次遍历wait_q 中的线程,如果发现其等待的条件已满足,调用 event_walk_op 从链表头部插入线程。
  • 当遍历完成后依次取出单链表中的线程,将其唤醒。

events 初始化

Z_EVENT_INITIALIZER

  • 静态初始化使用于为 k_event 全局对象设置初始值
#define Z\_EVENT\_INITIALIZER(obj) \
 { \
 .wait\_q = Z\_WAIT\_Q\_INIT(&obj.wait\_q), \
 .events = 0 \
 }

  • 该宏会将等待队列初始化为空
  • events 设置为0

void k_event_init(struct k_event *event)

  • k_event_init 为运行时初始化函数,其具体的实现由z_impl_k_event_init 完成, 该函数功能与 Z_EVENT_INITIALIZER 一致。
void z\_impl\_k\_event\_init(struct k\_event \*event)
{
	event->events = 0;
	event->lock = (struct k\_spinlock) {};

	SYS\_PORT\_TRACING\_OBJ\_INIT(k_event, event);

	z\_waitq\_init(&event->wait_q);

	z\_object\_init(event);
}

发布事件

void k_event_post(struct k_event *event, uint32_t events)

  • k_event_post 用于向事件对象发布指定的事件集,其实现由 z_impl_k_event_post 完成。
void z\_impl\_k\_event\_post(struct k\_event \*event, uint32\_t events)
{
	k\_event\_post\_internal(event, events, events);
}

static void k\_event\_post\_internal(struct k\_event \*event, uint32\_t events,
				  uint32\_t events_mask)
{
	k\_spinlock\_key\_t  key;
	struct k\_thread  \*thread;
	struct event\_walk\_data data;

	data.head = NULL;
	key = k\_spin\_lock(&event->lock);

	SYS\_PORT\_TRACING\_OBJ\_FUNC\_ENTER(k_event, post, event, events,
					events_mask);

	events = (event->events & ~events_mask) |
		 (events & events_mask);
	event->events = events;
	data.events = events;
	
	/\* 发布一个事件可能会唤醒多个被挂起的线程,为了将被影响的线程同时解挂,
 \* 需要完成以下步骤:
 \* 1、遍历等待队列并创建一个单链表用于解除挂起
 \* 2、将单链表中的线程依次解除挂起
 \* 3、将单链表中的线程设置为就绪态
 \*/
	
	/\* 将等待队列中满足条件的线程添加到单链表中 \*/
	z\_sched\_waitq\_walk(&event->wait_q, event_walk_op, &data);

	/\* 唤醒所有单链表中的线程 \*/
	if (data.head != NULL) {
		thread = data.head;
		struct k\_thread \*next;
		do {
			arch\_thread\_return\_value\_set(thread, 0);
			thread->events = events;
			next = thread->next_event_link;
			z\_sched\_wake\_thread(thread, false);
			thread = next;
		} while (thread != NULL);
	}

	z\_reschedule(&event->lock, key);

	SYS\_PORT\_TRACING\_OBJ\_FUNC\_EXIT(k_event, post, event, events,
				       events_mask);
}

设置事件

void k_event_set(struct k_event *event, uint32_t events)

  • k_event_set 和 k_event_post 的区别类似于C语言中 = 与 |= 之间的差别,k_event_set 会将事件对象中的事件赋值为 events,而 k_event_post 只会影响指定的位,未指定的位则保持不变。
void z\_impl\_k\_event\_set(struct k\_event \*event, uint32\_t events)
{
	k\_event\_post\_internal(event, events, ~0);
}

设置或清除事件

void k_event_set_masked(struct k_event *event, uint32_t events, uint32_t events_mask)

  • k_event_set_masked 会将 events_mask 中指定的事件清除,并设置 events 中指定的事件。
void z\_impl\_k\_event\_set\_masked(struct k\_event \*event, uint32\_t events,
			       uint32\_t events_mask)
{
	k\_event\_post\_internal(event, events, events_mask);
}

清除事件

k_event_clear(struct k_event *event, uint32_t events)

  • k_event_clear 用于将 events 指定的事件清除
void z\_impl\_k\_event\_clear(struct k\_event \*event, uint32\_t events)
{
	k\_event\_post\_internal(event, 0, events);
}

等待事件

等待选项

  • 在Zephyr中包含如下选项,用于设置等待方式
#define K\_EVENT\_WAIT\_ANY 0x00 /\* Wait for any events \*/
#define K\_EVENT\_WAIT\_ALL 0x01 /\* Wait for all events \*/
#define K\_EVENT\_WAIT\_MASK 0x01
#define K\_EVENT\_WAIT\_RESET 0x02 /\* Reset events prior to waiting \*/

  • 选项说明:
    • bit0 为 1,等待所有事件,bit0 为 0,等待其中任一事件
    • bit1 为 1,在调用 k_event_wait 时先清除所有事件,bit1 为 0,不清除。

uint32_t k_event_wait(struct k_event *event, uint32_t events, bool reset, k_timeout_t timeout)

  • k_event_wait 中包含4个参数:
    • events 等待的事件
    • reset 是否在调用 k_event_wait 时先清除所有事件
    • timeout 超时时间
  • k_event_wait 由 z_impl_k_event_wait 实现相应功能。
uint32\_t z\_impl\_k\_event\_wait(struct k\_event \*event, uint32\_t events,
			     bool reset, k\_timeout\_t timeout)
{
	uint32\_t options = reset ? K_EVENT_WAIT_RESET : 0;

	return k\_event\_wait\_internal(event, events, options, timeout);
}

  • 该函数中 options 的 bit0 为 0,代表任一事件发生即会返回
  • options 的 bit1 由 reset 决定,当 reset 为 true 时会先将所有事件清除,再等待事件。
static uint32\_t k\_event\_wait\_internal(struct k\_event \*event, uint32\_t events,
				      unsigned int options, k\_timeout\_t timeout)
{
	uint32\_t  rv = 0;
	unsigned int  wait_condition;
	struct k\_thread  \*thread;

	/\* 在中断中调用 k\_event\_wait\_internal 时不会进入等待 \*/
	\_\_ASSERT(((arch\_is\_in\_isr() == false) ||
		  K\_TIMEOUT\_EQ(timeout, K_NO_WAIT)), "");

	SYS\_PORT\_TRACING\_OBJ\_FUNC\_ENTER(k_event, wait, event, events,
					options, timeout);

	/\* 无等待事件,返回0 \*/
	if (events == 0) {
		SYS\_PORT\_TRACING\_OBJ\_FUNC\_EXIT(k_event, wait, event, events, 0);
		return 0;
	}

	wait_condition = options & K_EVENT_WAIT_MASK;
	thread = z\_current\_get();

	k\_spinlock\_key\_t  key = k\_spin\_lock(&event->lock);
**自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。**

**深知大多数嵌入式工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!**

**因此收集整理了一份《2024年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**

![img](https://img-blog.csdnimg.cn/img_convert/4ca1f0698c5c42f1a3d2c795770fa2b0.png)

![img](https://img-blog.csdnimg.cn/img_convert/c27b524a8a56da4ec5314762c1577416.jpeg)

![img](https://img-blog.csdnimg.cn/img_convert/a3c093be29e7a53bbd5442cad75be238.png)

 **既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!**

![img](https://img-blog.csdnimg.cn/img_convert/79ac835463d455e5edc48b3f0ac61f20.png)

![img](https://img-blog.csdnimg.cn/img_convert/f295682adb205d201804be7cf31bdbd2.png)

 

**由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**

**如果你觉得这些内容对你有帮助,可以+V:Vip1104z获取!!! (备注:嵌入式)**

<img src="https://img-community.csdnimg.cn/images/73bb5de17851459088c6af944156ee24.jpg" alt="img" style="zoom: 67%;" />



# 最后

**资料整理不易,觉得有帮助的朋友可以帮忙点赞分享支持一下小编~**

**你的支持,我的动力;祝各位前程似锦,offer不断,步步高升!!!**

图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**

**如果你觉得这些内容对你有帮助,可以+V:Vip1104z获取!!! (备注:嵌入式)**

<img src="https://img-community.csdnimg.cn/images/73bb5de17851459088c6af944156ee24.jpg" alt="img" style="zoom: 67%;" />



# 最后

**资料整理不易,觉得有帮助的朋友可以帮忙点赞分享支持一下小编~**

**你的支持,我的动力;祝各位前程似锦,offer不断,步步高升!!!**

**[更多资料点击此处获qu!!](https://bbs.csdn.net/topics/618376385)**
  • 10
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值