重新认识一下 epoll 的 ET 模式和 LT 模式吧?+ 源码验证

1、内核把就绪队列的任务拷贝到用户态,并清空就绪列表。这一点大家已经达成了共识。

2、ET 也就到此为止了,LT 不一定到此为止。这一点应该也是达成共识了吧,不会有人认为 LT 到此一定不止吧?那我们可以从这里来唠嗑唠嗑。

3、如果任务没处理完,LT 会把 fd 拷贝回就绪链表。下一次任务从内核态拷贝到用户态时这些任务会再次被发送给业务处理。这里就不知道我们是不是共识了哈。

那如果是这样,我是不是可以说:只要任务每次都处理完了,其实 LT 和 ET 就不知道区别在哪里了?

我是不是还可以说:如果业务没处理完,ET 就丢任务了。

那这么一看,我的猜想就很明显了。

但是吧,猜想归猜想,epoll 的源码又不长,以前也不是没看过。网上下一份,网上关于 epoll 源码剖析的文章也不少,阅读起来难度不会很高,那就花这么一两个小时的时间解决一下这个问题吧。


epoll 源码解读


我记得我曾经有一份 epoll 源码的,后来博客删着删着就给没了。。。

咱是要整份源码来一遍还是直击要害?

直击要害吧,今晚还有两个课题要做,一个叫:nginx 里的 epoll 是 ET 还是 LT?因为有人说,nginx的应用场景是可以把 ET 喂饱的。

另一个课题,叫:我今晚要把我的衣服都手洗了,不是洗衣机洗。

要源码剖析来这篇:深入了解epoll模型 – 开卷有益,早期做的一篇,优化过五六次,是我最喜欢的一篇博客。都是干货不像这里这么多废话。

ET 体现在哪里?

// 实际执行复制到用户空间的工作是由该函数体负责

static __poll_t ep_send_events_proc(struct eventpoll *ep, struct list_head *head,void *priv)

{

struct ep_send_events_data *esed = priv;

__poll_t revents;

struct epitem *epi, *tmp;

struct epoll_event __user *uevent = esed->events;

struct wakeup_source *ws;

poll_table pt;

init_poll_funcptr(&pt, NULL);

esed->res = 0;

/*

  • We can loop without lock because we are passed a task private list.

  • Items cannot vanish during the loop because ep_scan_ready_list() is

  • holding “mtx” during this call.

*/

lockdep_assert_held(&ep->mtx);

// lambda表达式

list_for_each_entry_safe(epi, tmp, head, rdllink) {

if (esed->res >= esed->maxevents)

break;

/*

  • Activate ep->ws before deactivating epi->ws to prevent

  • triggering auto-suspend here (in case we reactive epi->ws

  • below).

  • This could be rearranged to delay the deactivation of epi->ws

  • instead, but then epi->ws would temporarily be out of sync

  • with ep_is_linked().

*/

ws = ep_wakeup_source(epi);

if (ws) {

if (ws->active)

__pm_stay_awake(ep->ws);

__pm_relax(ws);

}

list_del_init(&epi->rdllink);

/*

  • If the event mask intersect the caller-requested one,

  • deliver the event to userspace. Again, ep_scan_ready_list()

  • is holding ep->mtx, so no operations coming from userspace

  • can change the item.

*/

revents = ep_item_poll(epi, &pt, 1);

if (!revents)

continue;

// 复制到用户空间

if (__put_user(revents, &uevent->events) ||

__put_user(epi->event.data, &uevent->data)) {

list_add(&epi->rdllink, head);

ep_pm_stay_awake(epi);

if (!esed->res)

esed->res = -EFAULT;

return 0;

}

esed->res++;

uevent++;

if (epi->event.events & EPOLLONESHOT)

epi->event.events &= EP_PRIVATE_BITS;

else if (!(epi->event.events & EPOLLET)) {

/*

  • If this file has been added with Level

  • Trigger mode, we need to insert back inside

  • the ready list, so that the next call to

  • epoll_wait() will check again the events

  • availability. At this point, no one can insert

  • into ep->rdllist besides us. The epoll_ctl()

  • callers are locked out by

  • ep_scan_ready_list() holding “mtx” and the

  • poll callback will queue them in ep->ovflist.

*/

list_add_tail(&epi->rdllink, &ep->rdllist);

ep_pm_stay_awake(epi);

}

}

return 0;

}

好,这时候就有一个疑问了是吧,那如果我读完了,是不是也被添加到 rdlist 里面了?

对啊,一视同仁啊。

那什么时候被清理掉?总不能一直在里面,然后每次提交给我的 fd 有一堆都要报错吧?

对啊,of course. Why not? 当然是要善后的,怎么能让它这么消耗性能?

(英语不太好,找这段整整花了我半个小时时间,然后我就纳闷儿了,检查 rd 链表上是否有空 fd,那空 fd 是因为 LT,这里为什么对 LT/ET一视同仁了?难道 ET 也会产生空 fd?)先存疑吧,说不定哪天我就懂了,现在能力只能看到这一步了。哪天有机会遇上大佬可以请教请教。

/**

  • ep_scan_ready_list - Scans the ready list in a way that makes possible for

  •                  the scan code, to call f_op->poll(). Also allows for
    
  •                  O(NumReady) performance.
    
  • @ep: Pointer to the epoll private data structure.

  • @sproc: Pointer to the scan callback.

  • @priv: Private opaque data passed to the @sproc callback.

  • @depth: The current depth of recursive f_op->poll calls.

  • @ep_locked: caller already holds ep->mtx

  • Returns: The same integer error code returned by the @sproc callback.

*/

static __poll_t ep_scan_ready_list(struct eventpoll *ep,

__poll_t (*sproc)(struct eventpoll *,

struct list_head *, void *),void *priv,

int depth, bool ep_locked)

{

__poll_t res;

int pwake = 0;

struct epitem *epi, *nepi;

LIST_HEAD(txlist);

lockdep_assert_irqs_enabled();

/*

  • We need to lock this because we could be hit by

  • eventpoll_release_file() and epoll_ctl().

*/

if (!ep_locked)

mutex_lock_nested(&ep->mtx, depth);

/*

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数同学面临毕业设计项目选题时,很多人都会感到无从下手,尤其是对于计算机专业的学生来说,选择一个合适的题目尤为重要。因为毕业设计不仅是我们在大学四年学习的一个总结,更是展示自己能力的重要机会。

因此收集整理了一份《2024年计算机毕业设计项目大全》,初衷也很简单,就是希望能够帮助提高效率,同时减轻大家的负担。
img
img
img

既有Java、Web、PHP、也有C、小程序、Python等项目供你选择,真正体系化!

由于项目比较多,这里只是将部分目录截图出来,每个节点里面都包含素材文档、项目源码、讲解视频

如果你觉得这些内容对你有帮助,可以添加VX:vip1024c (备注项目大全获取)
img

时减轻大家的负担。**
[外链图片转存中…(img-yFIDtbxu-1712591089705)]
[外链图片转存中…(img-DVEdWtzR-1712591089705)]
[外链图片转存中…(img-KjbR9qqX-1712591089706)]

既有Java、Web、PHP、也有C、小程序、Python等项目供你选择,真正体系化!

由于项目比较多,这里只是将部分目录截图出来,每个节点里面都包含素材文档、项目源码、讲解视频

如果你觉得这些内容对你有帮助,可以添加VX:vip1024c (备注项目大全获取)
[外链图片转存中…(img-V4SdzvAF-1712591089706)]

  • 23
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值