新人學習,歡迎指正

部分select.c代碼
應用層
select(maxfd+1,&rfds,NULL,NULL,NULL);
-------------------(系統呼叫)------------------------------
kernel-3.4.39/arch/arm/kernel$ vi calls.S
//系統呼叫相關的匯編檔案
CALL(sys_select)
VFS:vi -t sys_select
->SYSCALL_DEFINE5宏,5代表有五個引數,替換得到sys_select
SYSCALL_DEFINE5(select, int, n, fd_set __user *, inp,\
fd_set __user *, outp,fd_set __user *, exp, \
struct timeval __user *, tvp)
->
#define SYSCALL_DEFINE5(select, ...)
SYSCALL_DEFINEx(5, _select, __VA_ARGS__)
->
#define SYSCALL_DEFINEx(x,_select, ...)
__SYSCALL_DEFINEx(x, _select, __VA_ARGS__)
->
#define __SYSCALL_DEFINEx(x, _select, ...)
long sys_select(int n, fd_set __user * inp,
fd_set __user *outp,fd_set __user *exp,
struct timeval __user * tvp)
{
ret = core_sys_select(n, inp, outp, exp, to);
}
--------------------------------------------------------------
core_sys_select(n, inp, outp, exp, to);
//1.校驗最大的檔案描述符
struct fdtable *fdt;
fdt = files_fdtable(current->files);
max_fds = fdt->max_fds;
if (n > max_fds)
n = max_fds;
//2.分配檔案描述符的記憶體
bits = kmalloc(6 * size, GFP_KERNEL);
fds.in = bits;
fds.out = bits + size;
fds.ex = bits + 2*size;
//在內核空間分配的讀表,寫表,其他表的首地址
fds.res_in = bits + 3*size;
fds.res_out = bits + 4*size;
fds.res_ex = bits + 5*size;
//在內核空間分配的準備好的讀表,寫表,其他表的首地址
//3.將用戶空間的讀表,寫表,其他的表拷貝到內核空間
if ((ret = get_fd_set(n, inp, fds.in)) ===>copy_from_user
(ret = get_fd_set(n, outp, fds.out))
(ret = get_fd_set(n, exp, fds.ex)))
//4.檔案描述符的檢查,如果所有的檔案描述符的資料
都沒有準備好,行程休眠,否則將準備好的檔案描
述符放入到fds.res_in,fds.res_out,fds.res_ex
ret = do_select(n, &fds, end_time);
//5.判斷是否是信號喚醒的行程
ret = -ERESTARTNOHAND;
if (signal_pending(current))
goto out; ====>信號喚醒的就跳過拷貝
ret = 0;
//6.如果不是信號喚醒的休眠,將檔案描述符拷貝到用戶空間
if (set_fd_set(n, inp, fds.res_in) ||
set_fd_set(n, outp, fds.res_out) || ====>copy_to_user
set_fd_set(n, exp, fds.res_ex))
ret = -EFAULT;
---------------------------------------------------------------------
驅動:
unsigned int (*poll) (struct file *file,\
struct poll_table_struct *wait);
部分do_select代碼
int do_select(int n, fd_set_bits *fds, struct timespec *end_time)
{
struct poll_wqueues table;
poll_table *wait;
int retval, i;
unsigned long slack = 0;
retval = max_select_fd(n, fds);
//通過檔案描述符表中的對應的被設定
//為1的位來校驗最大的檔案描述符的值
n = retval;
//將校驗完的檔案描述符賦值給n
poll_initwait(&table);
//poll相關結構體的初始化
//只需要關心函式指標的初始化程序就行了
//函式指標,執行的是__pollwait
//在__pollwait會拿到你提交的等待佇列頭,然后
//在等待佇列頭后面添加當前行程的等待佇列項
retval = 0;
//retval是用來判斷是否需要退出檔案描述符遍歷
//的回圈的,
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;
//定義6個指標,將結構體中的6個指標
//賦值給這6個指標變數
for (i = 0; i < n; ++rinp, ++routp, ++rexp)
{
//用來取第幾個unsigned long型別的資料
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 += BITS_PER_LONG;
continue;
}
for (j = 0; j < BITS_PER_LONG; ++j, ++i, bit <<= 1)
{
//用來unsigned long型別中的第幾位的
file = fget_light(i, &fput_needed);
//這里的i就是獲取到的檔案描述符,fget_light
//通過檔案描述符找到file結構體
//fd->fd_array[fd]->struct file
//POLLIN
if (file)
{
f_op = file->f_op;
if (f_op && f_op->poll)
{
mask = (*f_op->poll)(file, wait);
}
//如果file存在,并且fops存在,并且fops中的
//poll函式存在,就呼叫這個存在的poll函式
//就會得到mask
if ((mask & POLLIN_SET) && (in & bit))
{
res_in |= bit;
//將當前的檔案描述符放到
//要回傳的檔案描述符表中
retval++;
}
if ((mask & POLLOUT_SET) && (out & bit))
{
res_out |= bit;
retval++;
}
if ((mask & POLLEX_SET) && (ex & bit))
{
res_ex |= bit;
retval++;
}
//如果mask中的POLLIN/POLLOUT/POLLEX被置位了
//將這些檔案描述符放到準備好的檔案描述表中
//并且將retval這個變數加1,只要retval不為0,
//死回圈就會被退出
}
}
}
if (retval || timed_out || signal_pending(current))
break;
//如果retval不為0,或者超時時間到了或者信號到來了
//這個死回圈就會被退出
if (!poll_schedule_timeout(&table, TASK_INTERRUPTIBLE,
to, slack))
//如果上述的條件都不滿足,回圈沒有退出,行程
//就進入休眠狀態
}
return retval;
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/285501.html
標籤:其他
