结构等待队列[网络编程]select流程分析
题记:写这篇博客要主是加深自己对结构等待队列的认识和总结实现算法时的一些验经和训教,如果有错误请指出,万分感谢。
int
do_select
(int n, fd_set_bits *fds, struct timespec *end_time)
ktime_t expire, *to = NULL;
struct poll_wqueues table;
poll_table *wait;
int retval, i, timed_out = 0;
unsigned long slack = 0;
rcu_read_lock();
retval = max_select_fd(n, fds);
rcu_read_unlock();
if (retval < 0)
return retval;
n = retval;
poll_initwait(&table); 对 poll_wqueues结构停止一些初始化
if (end_time && !end_time->tv_sec && !end_time->tv_nsec) {
wait = NULL;
timed_out = 1;
}
if (end_time && !timed_out)
slack = estimate_accuracy(end_time);
retval = 0;
for (;;) {
unsigned long *rinp, *routp, *rexp, *inp, *outp, *exp;
inp = fds->in; outp = fds->out; exp = fds->ex;
rinp = fds->res_in; routp = fds->res_out; rexp = fds->res_ex;
for (i = 0; i < n; ++rinp, ++routp, ++rexp) { 历遍每一个描述符
unsigned long in, out, ex, all_bits, bit = 1, mask, j;
unsigned long res_in = 0, res_out = 0, res_ex = 0;
const struct file_operations *f_op = NULL;
struct file *file = NULL;
in = *inp++; out = *outp++; ex = *exp++;
all_bits = in | out | ex;
if (all_bits == 0) {
i += __NFDBITS; 如果这个字没有待查找的描述符, 跳过这个长字(32位)
continue;
}
for (j = 0; j < __NFDBITS; ++j, ++i, bit <<= 1) { 历遍每一个长字里的每一位个
int fput_needed;
if (i >= n)
break;
if (!(bit & all_bits))
continue;
file = fget_light(i, &fput_needed); 失掉指位定对应的fd的file结构
if (file) {
f_op = file->f_op;
mask = DEFAULT_POLLMASK;
if (f_op && f_op->poll) {
wait_key_set(wait, in, out, bit);
mask = (*f_op->poll)(file, wait); 在这里循环调用所监测的fd_set内的有所件文描述符对应的poll数函
}
fput_light(file, fput_needed);
if ((mask & POLLIN_SET) && (in & bit)) {
res_in |= bit; 如果是这个描述符可读, 将这位个置位
retval++; 返回描述符个数加1
wait = NULL;
}
if ((mask & POLLOUT_SET) && (out & bit)) {
res_out |= bit; 如果是这个描述符有异常错误, 将这位个置位
retval++; 返回描述符个数加1
wait = NULL;
}
if ((mask & POLLEX_SET) && (ex & bit)) {
res_ex |= bit; 如果是这个描述符有异常错误, 将这位个置位
retval++; 返回描述符个数加1
wait = NULL;
}
}
}
if (res_in)
*rinp = res_in;
if (res_out)
*routp = res_out;
if (res_ex)
*rexp = res_ex;
cond_resched();
}
wait = NULL;
if (retval || timed_out || signal_pending(current))
break; 跳出循环 返回结果
if (table.error) {
retval = table.error;
break;
}
if (end_time && !to) {
expire = timespec_to_ktime(*end_time);
to = &expire;
}
if (!poll_schedule_timeout(&table, TASK_INTERRUPTIBLE, 就寝,可由信号唤醒
to, slack))
timed_out = 1;
}
poll_freewait(&table);
return retval;
}
主要结构体
生活中受伤难免,失败跌倒并不可怕,可怕的是因此而一蹶不振,失去了对人生的追求与远大的理想。没有一个人的前进道路是平平稳稳的,就算是河中穿梭航行的船只也难免颠簸,生活中所遇上的坎坷磨难不是偶尔给予的为难,而是必然所经受的磨练。
unsigned long *in, *out, *ex;
unsigned long *res_in, *res_out, *res_ex;
} fd_set_bits; 这个结构体保存了select在户用态的数参
poll_table pt;
struct poll_table_page *table;
struct task_struct *polling_task; 保存前当调用select的户用进程struct task_struct结构体
int triggered; 前当户用进程被唤醒后置成1,以免该进程接着进就寝
int error;
int inline_index; 数组inline_entries的引用下标
struct poll_table_entry inline_entries[N_INLINE_POLL_ENTRIES];
};
struct poll_table_page * next;
struct poll_table_entry * entry;
struct poll_table_entry entries[0];
};
struct file *filp;
unsigned long key;
wait_queue_t wait; 内嵌了一个待等列队
wait_queue_head_t *wait_address;
};
{
init_poll_funcptr(&pwq->pt, __pollwait); 保存回调数函
pwq->polling_task = current; 置设polling_task为前当进程
pwq->triggered = 0;
pwq->error = 0;
pwq->table = NULL;
pwq->inline_index = 0;
}
{
pt->qproc = qproc;
pt->key = ~0UL; /* all events enabled */
}
{
struct socket *sock;
sock = file->private_data; 失掉socket结构,存于file的私有数据区中 这里就从fd转化为对对应socket结构的作操了
return sock->ops->poll(file, sock, wait);
struct sk_buff_head sk_write_queue; 这些列队是不是可读,可写,以及其他一些状态的断判,体具的不进入分析了
unsigned int datagram_poll(struct file *file, struct socket *sock,
poll_table *wait)
{
struct sock *sk = sock->sk;
unsigned int mask;
sock_poll_wait(file, sk->sk_sleep, wait); 将wait加入到sock的sk_sleep待等列队头中
mask = 0;
上对面各种可读,可写,异常错误等状态断判,返回mask
/* exceptional events? */
if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
mask |= POLLERR;
if (sk->sk_shutdown & RCV_SHUTDOWN)
mask |= POLLRDHUP;
if (sk->sk_shutdown == SHUTDOWN_MASK)
mask |= POLLHUP;
/* readable? */
if (!skb_queue_empty(&sk->sk_receive_queue) ||
(sk->sk_shutdown & RCV_SHUTDOWN))
mask |= POLLIN | POLLRDNORM;
/* Connection-based need to check for termination and startup */
if (connection_based(sk)) {
if (sk->sk_state == TCP_CLOSE)
mask |= POLLHUP;
/* connection hasn't started yet? */
if (sk->sk_state == TCP_SYN_SENT)
return mask;
}
/* writable? */
if (sock_writeable(sk))
mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
else
set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
return mask;
}
static inline void sock_poll_wait(struct file *filp,
wait_queue_head_t *wait_address, poll_table *p)
{
if (p && wait_address) {
poll_wait(filp, wait_address, p);
smp_mb();
}
}
{
if (p && wait_address)
p->qproc(filp, wait_address, p); 这里qproc即为 init_poll_funcptr(&pwq->pt, __pollwait); 保存回调数函
}
poll_table *p)
{
struct poll_wqueues *pwq = container_of(p, struct poll_wqueues, pt); 从poll_table结构失掉poll_wqueues 结构
struct poll_table_entry * entry = poll_get_entry(pwq); 得获一个poll_table_entry
if (!entry)
return;
get_file(filp);
entry->filp = filp; 保存file结构变量
entry->wait_address = wait_address; 这里wait_address为sk->sk_sleep结构
init_waitqueue_func_entry(&entry->wait, pollwake); 初始化待等列队项,pollwake是唤醒该待等列队项时候调用的数函
entry->wait.private = pwq; 将poll_wqueues作为该待等列队项的私有数据,面后应用
add_wait_queue(wait_address, &entry->wait);
}
我们看下就寝
ktime_t *expires, unsigned long slack)
{
int rc = -EINTR;
set_current_state(state);
if (!pwq->triggered) 这个triggered在什么时候被置1的呢?只要有一个fd对应的设备将前当应用进程唤醒后将会把它置设成1
rc = schedule_hrtimeout_range(expires, slack, HRTIMER_MODE_ABS);
__set_current_state(TASK_RUNNING);
set_mb(pwq->triggered, 0);
return rc;
}
看下唤醒进程:
static int pollwake(wait_queue_t *wait, unsigned mode, int sync, void *key)
{
struct poll_table_entry *entry;
entry = container_of(wait, struct poll_table_entry, wait); 从wait失掉poll_table_entry 结构
if (key && !((unsigned long)key & entry->key)) 断判key,检查是不是有错误唤醒
return 0;
return __pollwake(wait, mode, sync, key);
}
{
struct poll_wqueues *pwq = wait->private;
DECLARE_WAITQUEUE(dummy_wait, pwq->polling_task);
smp_wmb();
pwq->triggered = 1;
return default_wake_function(&dummy_wait, mode, sync, key); 将待等进程从待等列队上摘下,加入运行进程列队等一系列复杂作操,达到唤醒目的
}
文章结束给大家分享下程序员的一些笑话语录: IBM和波音777
波音777是有史以来第一架完全在电脑虚拟现实中设计制造的飞机,所用的设备完全由IBM公司所提供。试飞前,波音公司的总裁非常热情的邀请IBM的技术主管去参加试飞,可那位主管却说道:“啊,非常荣幸,可惜那天是我妻子的生日,So..”..
波音公司的总载一听就生气了:“胆小鬼,我还没告诉你试飞的日期呢!”
转载于:https://www.cnblogs.com/xinyuyuanm/archive/2013/04/21/3033478.html
结构等待队列[网络编程]select流程分析相关推荐
- linux网络编程--select/poll/epoll 详解
目录 参考链接 epoll函数 close epoll event EL/LT ET Edge Trigger 边沿触发工作模式 LT Level Trigger 水平触发工作模式 epoll 源码解 ...
- C++网络编程Select函数用法
Select在Socket编程中还是比较重要的,可是对于初学Socket的人来说都不太爱用Select写程序,他们只是习惯写诸如 connect.accept.recv或recvfrom这样的阻塞程序 ...
- Android 网络请求OkHttp3流程分析
基本概念 首先从使用出发,其次再结合源码来分析OkHttp3的内部实现的,建议大家下载 OkHttp 源码跟着本文,过一遍源码.首先来看一下OkHttp3的请求代码. OkHttpClient cli ...
- UNIX网络编程——select函数的并发限制和 poll 函数应用举例
http://blog.csdn.net/chenxun_2010/article/details/50489577 一.用select实现的并发服务器,能达到的并发数,受两方面限制 1.一个进程能打 ...
- socket网络编程——TCP编程流程及端口号占用问题
1.TCP编程流程 1.1TCP服务器端客户端及方法介绍 TCP 提供的是面向连接的.可靠的.字节流服务.TCP 的服务器端和客户端编程流程如下: socket()方法是用来创建一个套接字,有了套接字 ...
- socket网络编程——套接字地址结构
声明:此博客是本人根据老师课件总结的,如有抄袭行为,本人会即刻删除. 1.主机字节序列和网络字节序列 主机字节序列分为大端字节序和小端字节序,不同的主机采用的字节序列可能不同.大端字节序是指一个整数的 ...
- 套接字编程-TCP网络编程
文章目录 套接字地址结构 通用套接字地址数据结构 以太网协议的套接字地址数据结构 Netlink协议套接字地址结构 TCP网络编程 套接字初始化socket() domain type protoco ...
- L6网络编程--IO多路复用(day6)
目录 一.I/O模型 二.阻塞I/O模式 : 1.读阻塞 2.写阻塞 三.非阻塞模式I/O 1.非阻塞模式的实现 fcntl()函数 四.多路复用I/O 基本常识: 多路复用服务器模型:编辑 sel ...
- 实习秋招linux和网络编程知识点总结
实习/秋招时按自己需求总结的知识点,内容并不十分详细,建议选择性阅读. 部分图片已失效. git常用命令速查表 git回滚 https://www.jianshu.com/p/f7451177476a ...
- C++网络编程(一):TCP套接字编程
目录 基本数据结构 TCP服务器端的默认函数调用顺序 TCP客户端的默认函数调用情况 TCP网络编程主要流程 TCP客户端套接字的地址分配 TCP套接字的I/O缓存 代码实例 面试常见问题详解 参考资 ...
最新文章
- Leetcode: 101. Symmetric Tree
- PHP同时连接多个mysql数据库_php如何同时连接多个数据库
- 使用iostat分析IO性能
- 库存管理-历史库存和收发存系列-MB5B
- leetcode 705. 设计哈希集合
- spring学习(50):延迟加载
- 挂载报错:“/dev/vda1 is apparently in use by the system;”
- 数据分析的常用工具有哪些
- 微信公众号推文怎么做?
- HEVC之CU\PU\TU
- mysql的sql语句没错但是报错_sql语句没错·但是却报错,怎么回事?
- 大数据架构师——音乐数据中心平台离线数仓综合项目(一)
- 《深入理解Java虚拟机》内存管理机制 部分 读书笔记
- 用C++制作一款电话簿
- python输入一个字符串、计算其中小写字符的个数_利用键盘录入,输入一个字符串,统计该字符串中各个字符的数量,并输出(c/c++实现)...
- MySQL索引数据结构二叉树、红黑树、B-Tree、B+Tree、Hash
- axis2 默认端口_axis2 webservice 问题,高手进,急!!!!!!!!!!!!!!!!!!!!!
- iOS代码质量要求_苹果发布 iOS amp; iPadOS 13.1 beta 4 版本;Dart 2.5正式公布;SwiftUI View的生命周期...
- Win10常用的快捷键和触摸板操作合集
- Visual Studio 2019 和 qt 5.15.1 下 opengl 的运用 - Lighting - 01 - Colors