编辑2:我正在实现< stdio.h>作为能够打开/ proc(以及其他虚拟文件系统)的内核模块,类似于FILE并处理类似于< stdio.h>的输入和输出.你可以找到项目here.
我发现了很多关于内核如何将大量数据写入/ proc(用户空间程序)的问题,但是没有什么可以相反的.让我详细说明一下:
这个问题基本上是关于输入被标记化的算法(例如,int或int和string的混合等),因为数据可能在多个缓冲区之间被破坏.
例如,假设以下数据被发送到内核模块:
12345678 81234567 78123456 67812345 5678 1234 45678123 3456 7812 23456781
为了这个例子,我们假设Linux提供/ proc处理程序的页面大小是20字节(与真正的4KB相比).
从/ proc(在内核模块中)读取数据的功能然后可以看到数据:
call 1: "12345678 81234567 78" call 2: "123456 67812345 5678" call 3: " 1234 45678123 3456 " call 4: "7812 23456781"
正如你可以看到的,当第一次通话中读取78时,它不应该被处理,直到下一个帧决定是78是整数还是一帧之间.
现在我发现seq_file
s显然只有当内核想要将数据写入用户而不是读取时(或者可能是HOWTO写得很糟糕).
我做了什么
到目前为止,我已经提供了以下解决方案(我正在从内存写入,所以我可能会错过一些错误检查,但是与我无关):
在初始化阶段(如init_module):
initialize mutex1 to 1 and mutex2 to 0 create /proc entry call data_processor
/ proc读者:
1. down(mutex1) /* down_interruptible of course,but let's not get into details */ 2. copy_from_user to an internal buffer buffer_index = 0 data_length = whatever the size is 3. strip spaces from end of buffer (except if all left from buffer is 1 space) if so,there_was_space_after = 1 else 0 4. up(mutex2)
我会解释为什么我稍后放空
get_int函数:
wait_for_next = 0 number_was_cut = 0 last_number = 0 do { 1. down(mutex2) 2. if (number_was_cut && !isdigit(buffer[buffer_index])) break /* turns out it wasn't really cut as beginning of next buffer is ' ' */ number_was_cut = 0 wait_for_next = 0 3. while (buffer_index < data_length && !isdigit(buffer_index[buffer_index])) ++buffer_index; /* skip white space */ 4. while (buffer_index < data_length && isdigit(buffer[buffer_index])) last_number = last_number * 10 + buffer[buffer_index++] - '0'; 5. if (buffer_index >= data_length && !there_was_space_after) number_was_cut = 1 wait_for_next = 1 up(mutex1) /* let more data come in */ else up(mutex2) /* let get_int continue */ break } while (wait_for_next) return last_number
data_processor函数(例如):
int first_num = get_int() int sencod_num = get_int() for i = first_num to second_num do_whatever(get_int())
说明:首先,参见data_processor.它不会涉及到如何读取数据的复杂性,所以它只是获得整数,并做任何它想要的.现在看看/ proc读者.它基本上等待data_processor调用get_int足够的时间来消耗所有当前数据(步骤1),然后将下一个缓冲区复制到内部存储器中,从而允许data_processor继续(步骤2).然后,需要删除尾随空格,以便get_int可以被简化(步骤3).最后,它向get_int发出信号,它可以开始读取数据(步骤4).
get_int函数首先等待数据到达(步骤1)(忽略现在的步骤2),它跳过任何不需要的字符(步骤3),然后开始读取数字(步骤4).阅读数字的结尾是两种可能性:达到缓冲区的结束(在这种情况下,如果/ proc读取器没有剥离任何空格,则可以在帧之间剪切数字)或满足白色空间.在前一种情况下,需要通知/ proc读取器读取更多的数据,并等待另一个周期将剩余的数字附加到当前数据,而在后一种情况下,它返回数字(步骤5).如果从最后一帧继续,请检查新帧是否以数字开头.如果没有,那么以前的号码实际上是一个整数,应该被返回.否则,需要继续将数字追加到最后一个号码(步骤2).
问题
这种方法的主要问题是过于复杂.当get_string被添加或读取整数可以是十六进制时,它变得复杂得多.基本上,你必须重新创建sscanf!请注意,在这个简单的例子中,sscanf可以在get_int的第4步而不是while循环中使用(或者也可以使用get_string,但是当十六进制输入也是可能的时候会变得更棘手)(想象十进制数在0和x0212ae4之间切换)即使如此,它只是取代了get_int的第四步,其余的东西仍然保留下来.
它实际上让我有很多错误和沉重的测试来完善所有的特殊情况.这就是为什么它看起来不优雅的另一个原因.
问题
我想知道是否有更好的方法来处理这个问题.我知道使用共享内存可能是一个选择,但是我正在寻找一个这个任务的算法(更多的好奇心,因为我已经有我的工作解决方案).进一步来说:
>在Linux内核中是否有一个已经实现的方法,可以像普通的C FILE那样对待,您可以从中获取数据,并将数据分解成页面本身?
>如果没有,我是否过度复杂的事情,我是否缺少一个明显的简单解决方案?
>我相信fscanf面临着类似的问题.这是如何处理的?
侧面的问题:这是一个可怕的事情,我阻止/ proc读取器上的互斥体?我的意思是,写数据可能是阻塞的,但我不知道通常是在用户空间还是内核空间中发生.