linux内核循环,循环缓冲区(参考linux内核Kfifo)

1 循环缓冲区在一些竞争问题上提供了一种免锁的机制,免锁的前提是,生产者和消费 2 都只有一个的情况下,否则也要加锁。下面就内核中提取出来,而经过修改后的fifo进 3 行简要的分析。 4 5 先看其只要数据结构: 6 struct my_fifo { 7 unsigned char *buffe

1循环缓冲区在一些竞争问题上提供了一种免锁的机制,免锁的前提是,生产者和消费

2都只有一个的情况下,否则也要加锁。下面就内核中提取出来,而经过修改后的fifo进

3行简要的分析。

4

5先看其只要数据结构:

6struct my_fifo {

7unsignedchar *buffer;/*the buffer holding the data*/

8unsignedint size;/*the size of the allocated buffer*/

9unsignedint in;/*data is added at offset (in % size)*/

10unsignedint out;/*data is extracted from off. (out

% size)*/

11};

12也不用多说,一看就明白。size, in, out 都设成无符号型的,因为都不存在负值的情

13型。

14

15/*

16form kernel/kfifo.c

17*/

18

19#include

20#include

21#include

22

23#define min(a,b) ((a) < (b) ? (a):(b))

24/*

25my_fifo_init

26*/

27struct my_fifo *my_fifo_init(unsignedchar *buffer,unsigned

int size)

28{

29struct my_fifo *fifo;

30

31

32fifo = malloc(sizeof(struct my_fifo));

33if (!fifo)

34returnNULL;

35

36fifo->buffer = buffer;

37fifo->size = size;

38fifo->in = fifo->out = 0;

39

40return fifo;

41}

42这个初始化fifo结构的函数一般也不会在应用层里进行调用,而是被下面的fifo_alloc

43调用。依我的观点来看,这两个函数合成一个函数会更加的清晰,但是这一情况只针对

buffer是系统开辟的空间,如果buffer的空间是由其它的函数来提供,就只能用上面的这个函数。

44/*

45my_fifo_alloc

46*/

47struct my_fifo *my_fifo_alloc(unsignedint size)

48{

49unsignedchar *buffer;

50struct my_fifo *ret;

51

52/*

53* round up to the next power of 2, since our 'let the indices

54* wrap' tachnique works only in this case.

55*/

56

57buffer = malloc(size);

58if (!buffer)

59returnNULL;

60

61ret = my_fifo_init(buffer, size);

62

63if (ret ==NULL)

64free(buffer);

65

66return ret;

67}

68/*

69* my_fifo_free

70*/

71void my_fifo_free(struct my_fifo *fifo)

72{

73free(fifo->buffer);

74free(fifo);

75}

76

77这两个函数也不作过多的分析,都很清晰。

test.jsp?url=http%3A%2F%2Fhi.csdn.net%2Fattachment%2F201202%2F20%2F0_1329701771hnm1.gif&refer=http%3A%2F%2Fblog.csdn.net%2Fjnu_kinke%2Farticle%2Fdetails%2F7274651

78/*

79my_fifo_put()

80*/

81unsignedint my_fifo_put(struct my_fifo *fifo,

82unsignedchar *buffer,

unsigned int len)

83{

84unsignedint l;

85

86len = min(len, fifo->size - fifo->in + fifo->out);/*可能是缓冲区的空闲长度或者要写长度*/

87

88/*first put the data starting from fifo->in to buffer end*/

89l = min(len, fifo->size - (fifo->in & (fifo->size -1)));

90memcpy(fifo->buffer + (fifo->in & (fifo->size -1)), buffer, l);

91

92/*then put the rest (if any) at the beginning of the buffer*/

93memcpy(fifo->buffer, buffer + l, len - l);

94

95fifo->in += len;

96

97return len;

98}

99

100/*

101my_fifo_get

102*/

103unsignedint my_fifo_get(struct my_fifo *fifo,

104unsignedchar *buffer,

unsigned int len)

105{

106unsignedint l;

107

108len = min(len, fifo->in - fifo->out); /*可读数据*/

109

110/*first get the data from fifo->out until the end of the buffer*/

111l = min(len, fifo->size - (fifo->out & (fifo->size -1)));

112memcpy(buffer, fifo->buffer + (fifo->out & (fifo->size -1)), l);

113

114/*then get the rest (if any) from the beginning of the buffer*/

115memcpy(buffer + l, fifo->buffer, len - l);

116

117fifo->out += len;

118

119return len;

120}

121这两个读写结构才是循环缓冲区的重点。在fifo结构中,size是缓冲区的大小,是由用

122户自己定义的,但是在这个设计当中要求它的大小必须是2的幂次。

123当in==out时,表明缓冲区为空的,当(in-out)==size 时,说明缓冲区已满。

124

125我们看下具体实现,在86行处如果size-in+out ==0,也即获得的len值会0,而没有数

126据写入到缓冲区中。所以在设计缓冲区的大小的时候要恰当,读出的速度要比定入的速

127度要快,否则缓冲区满了会使数据丢失,可以通过成功写入的反回值来做判断尝试再次

128写入.

129另一种情况则是缓冲区有足够的空间给要写入的数据,但是试想一下,如果空闲的空间

130在缓冲的首尾两次,这又是如何实现呢?这部分代码实现得非常巧妙。

131我们看fifo->in &(fifo->size-1) 这个表达式是什么意思呢?我们知道size是2的幂次

132项,那么它减1即表示其值的二进制所有位都为1,与in相与的最终结果是in%size,比

133size要小,所以看in及out的值都是不断地增加,但再相与操作后,它们即是以size为

134周期的一个循环。89行就是比较要写入的数据应该是多少,如果缓冲区后面的还有足够

135的空间可写,那么把全部的值写到后面,否则写满后面,再写到前面去93行。

136读数据也可以作类似的分析,108行表示请求的数据要比缓冲区的数据要大时,只

137读取缓冲区中可用的数据。

138

139staticinline

void my_fifo_reset(struct my_fifo *fifo)

140{

141fifo->in = fifo->out = 0;

142}

143

144staticinline

unsigned int my_fifo_len(struct my_fifo *fifo)

145{

146return fifo->in - fifo->out;

147}

148

149在头文件里还有缓冲区置位及返回缓冲区中数据大小两个函数,很简单,不必解释。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值