kk Blog —— 通用基础

date [-d @int|str] [+%s|"+%F %T"]

编译GT-S5830内核

下载源码 http://opensource.samsung.com/reception/receptionSub.do?method=sub&sub=F&searchValue=s5830

编译器 https://github.com/AdiPat/Android_Toolchains

编译方法看解开的Kernel的readme。但先注意以下一些再编译:

注意S5830有些驱动,驱动好像是没开源。解开正在用的boot.img,

1
2
$ strings boot.img-ramdisk/lib/modules/fsr.ko | grep vermagic
vermagic=2.6.35.7-perf-CL382966 preempt mod_unload ARMv6

能看到版本为2.6.35.7-perf-CL382966 或者 直接看手机上:设置->关于手机->内核版本。

检查内核的make_kernel_GT-S5830.sh的对应的config(在arch/arm/configs下)文件的CONFIG_LOCALVERSION=XXX,
XXX改成和你手机的这部分'-perf-CL382966'一模一样,不一样这些模块加载不上去,导致开机一直停在三星log那。

编译好后,cp *.ko 到 boot.img-ramdisk/lib/modules/,然后按照 这里 方法重新生成boot.img, 记得zImage用你编译的,在arch/arm/boot/zImage

1
mkbootimg --kernel zImage --ramdisk no_ko_ramdisk.cpio.gz --base 13600000 --ramdisk_offset FF8000 --pagesize 4096 -o 3.4_noko_boot.img

收包软中断和netif_rx

初始化报文接收软中断
1
2
3
4
5
6
static int __init net_dev_init(void)
{
	......
	open_softirq(NET_RX_SOFTIRQ, net_rx_action);
	......
}
报文接收软中断的处理函数net_rx_action详解:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
static void net_rx_action(struct softirq_action *h)
{
	/*取得本地cpu 的softnet_data 的poll_list  链表*/
	struct list_head *list = &__get_cpu_var(softnet_data).poll_list;
	/*设置软中断处理程序一次允许的最大执行时间为2个jiffies*/
	unsigned long time_limit = jiffies + 2;

	/*设置软中断接收函数一次最多处理的报文个数为 300 */
	int budget = netdev_budget;
	/*关闭本地cpu的中断,下面判断list是否为空时防止硬中断抢占*/
	local_irq_disable();
	/*循环处理pool_list 链表上的等待处理的napi*/
	while (!list_empty(list))
	{
		struct napi_struct *n;
		int work, weight;

		/*如果处理报文超出一次处理最大的个数
		  或允许时间超过最大时间就停止执行,
		  跳到softnet_break 处*/
		if (unlikely(budget <= 0 || time_after(jiffies, time_limit)))
		{
			goto softnet_break;
		}
		/*使能本地中断,上面判断list为空已完成,下面调用NAPI
		  的轮询函数是在硬中断开启的情况下执行*/
		local_irq_enable();

		/* 取得softnet_data pool_list 链表上的一个napi,
		   即使现在硬中断抢占软中断,会把一个napi挂到pool_list的尾端
		   软中断只会从pool_list 头部移除一个pool_list,这样不存在临界区*/
		n = list_entry(list->next, struct napi_struct, poll_list);
		/*用weighe 记录napi 一次轮询允许处理的最大报文数*/
		weight = n->weight;
		/* work 记录一个napi总共处理的报文数*/
		work = 0;

		/*如果取得的napi状态是被调度的,就执行napi的轮询处理函数*/
		if (test_bit(NAPI_STATE_SCHED, &n->state))
		{
			work = n->poll(n, weight);
		}
		WARN_ON_ONCE(work > weight);
		/*预算减去已经处理的报文数*/
		budget -= work;
		/*禁止本地CPU 的中断,下面会有把没执行完的NAPI挂到softnet_data
		  尾部的操作,和硬中断存在临界区。同时while循环时判断list是否
		  为空时也要禁止硬中断抢占*/
		local_irq_disable();

		/*如果napi 一次轮询处理的报文数正好等于允许处理的最大数,
		  说明一次轮询没处理完全部需要处理的报文*/
		if (unlikely(work == weight))
		{
			/*如果napi已经被禁用,就把napi 从 softnet_data 的pool_list 上移除*/
			if (unlikely(napi_disable_pending(n)))
			{
				local_irq_enable();
				napi_complete(n);
				local_irq_disable();
			}
			else
			{
				/*否则,把napi 移到 pool_list 的尾端*/
				list_move_tail(&n->poll_list, list);
			}
		}
	}
out:
	local_irq_enable();
	return;

	/*如果处理时间超时,或处理的报文数到了最多允许处理的个数,
	  说明还有napi 上有报文需要处理,调度软中断。
	  否则,说明这次软中断处理完全部的napi上的需要处理的报文,不再需要
	  调度软中断了*/
softnet_break:
	__get_cpu_var(netdev_rx_stat).time_squeeze++;
	__raise_softirq_irqoff(NET_RX_SOFTIRQ);
	goto out;
}
虚拟NAPI backlog 的轮询函数process_backlog():

参数:
napi : 本地cpu上softnet_data 的backlog .
quota : 一次轮询可以处理的最多报文数。

函数详解:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
static int process_backlog(struct napi_struct *napi, int quota)
{
	int work = 0;

	/*取得本地CPU上的softnet_data  数据*/
	struct softnet_data *queue = &__get_cpu_var(softnet_data);

	/*开始计时,一旦允许时间到,就退出轮询*/
	unsigned long start_time = jiffies;
	napi->weight = weight_p;

	/*循环从softnet_data 的输入队列取报文并处理,直到队列中没有报文了,
	 或处理的报文数大于了允许的上限值了,
	 或轮询函数执行时间大于一个jiffies 了
	*/
	do
	{
		struct sk_buff *skb;
		/*禁用本地中断,要存队列中取skb,防止抢占*/
		local_irq_disable();

		/*从softnet_data 的输入队列中取得一个skb*/
		skb = __skb_dequeue(&queue->input_pkt_queue);

		/*如果队列中没有skb,则使能中断并退出轮询*/
		if (!skb)
		{
			/*把napi 从 softnet_data 的 pool_list 链表上摘除*/
			__napi_complete(napi);
			/*使能本地CPU的中断*/
			local_irq_enable();
			break;
		}
		/*skb 已经摘下来了,使能中断*/
		local_irq_enable();

		/*把skb送到协议栈相关协议模块进行处理,详细处理见后续章节*/
		netif_receive_skb(skb);
	} while (++work < quota && jiffies == start_time);
	/*返回处理报文个数*/
	return work;
}
linux旧的收包方式提供给驱动的接口netif_rx():
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
int netif_rx(struct sk_buff *skb)
{
	struct softnet_data *queue;
	unsigned long flags;

	/*如果接收skb的时间戳没设定,设定接收时间戳*/
	if (!skb->tstamp.tv64)
	{
		net_timestamp(skb);
	}

	/*禁止本地cpu的中断*/
	local_irq_save(flags);

	/*取得本地cpu的softnet_data*/
	queue = &__get_cpu_var(softnet_data);
				   
	/*每个CPU都有一个统计数据,增加统计数据*/
	__get_cpu_var(netdev_rx_stat).total++;

	/*如果本地CPU的输入队列中的skb 个数小于允许的最多的个数*/
	if (queue->input_pkt_queue.qlen <= netdev_max_backlog)
	{
		/*如果本地cpu的输入队列长度不为0,表示输入队列已经有skb了,
		并且特殊的napi backlog 已经挂入了softnet_data  的
		pool_list上了*/
		if (queue->input_pkt_queue.qlen)
		{
enqueue:
			/*把skb 放入CPU的输入队列 input_pkt_queue*/
			__skb_queue_tail(&queue->input_pkt_queue, skb);
					  
			/*使能中断 并 返回*/
			local_irq_restore(flags);
			return NET_RX_SUCCESS;
		}
		/*如果输入队列为空,则把 特殊的napi backlog 挂到softnet_data
		的 pool_list 上 并返回把skb放入输入队列并返回*/
		napi_schedule(&queue->backlog);
		goto enqueue;
	}
	/*如果本地cpu的输入队列已经满了,则丢弃报文,
	  并增加丢包计数并返回*/
	__get_cpu_var(netdev_rx_stat).dropped++;
	local_irq_restore(flags);

	kfree_skb(skb);
	return NET_RX_DROP;
}

ruby字符串处理函数

1.返回字符串的长度
1
str.length => integer
2.字符串索引index
1
2
3
4
5
6
7
8
9
10
11
12
13
str.index(substring [, offset])   => fixnum or nil
str.index(fixnum [, offset])      => fixnum or nil
str.index(regexp [, offset])      => fixnum or nil

Returns the index of the first occurrence of the given substring, character (fixnum), 
or pattern (regexp) in str. Returns nil if not found. If the second parameter is present, 
it specifies the position in the string to begin the search.

   "hello".index('e')             #=> 1
   "hello".index('lo')            #=> 3
   "hello".index('a')             #=> nil
   "hello".index(101)             #=> 1
   "hello".index(/[aeiou]/, -3)   #=> 4
从尾到头rindex
1
2
3
4
5
6
7
8
9
10
11
12
13
str.rindex(substring [, fixnum])   => fixnum or nil
str.rindex(fixnum [, fixnum])   => fixnum or nil
str.rindex(regexp [, fixnum])   => fixnum or nil

Returns the index of the last occurrence of the given substring, character (fixnum), 
or pattern (regexp) in str. Returns nil if not found. If the second parameter is present, 
it specifies the position in the string to end the search---characters beyond this point will not be considered.

   "hello".rindex('e')             #=> 1
   "hello".rindex('l')             #=> 3
   "hello".rindex('a')             #=> nil
   "hello".rindex(101)             #=> 1
   "hello".rindex(/[aeiou]/, -2)   #=> 1
3.判断字符串中是否包含另一个串
1
2
3
4
str.include? other_str => true or false
"hello".include? "lo"   #=> true
"hello".include? "ol"   #=> false
"hello".include? ?h     #=> true
4.字符串插入
1
2
3
4
5
6
7
str.insert(index, other_str) => str
"abcd".insert(0, 'X')    #=> "Xabcd"
"abcd".insert(3, 'X')    #=> "abcXd"
"abcd".insert(4, 'X')    #=> "abcdX"
"abcd".insert(-3, 'X')
-3, 'X')   #=> "abXcd"
"abcd".insert(-1, 'X')   #=> "abcdX"
5.字符串分隔,默认分隔符为空格
1
2
3
4
5
6
7
8
9
str.split(pattern=$;, [limit]) => anArray
" now's the time".split        #=> ["now's", "the", "time"]
"1, 2.34,56, 7".split(%r{,\s*}) #=> ["1", "2.34", "56", "7"]
"hello".split(//)               #=> ["h", "e", "l", "l", "o"]
"hello".split(//, 3)            #=> ["h", "e", "llo"]
"hi mom".split(%r{\s*})         #=> ["h", "i", "m", "o", "m"]
"mellow yellow".split("ello")   #=> ["m", "w y", "w"]
"1,2,,3,4,,".split(',')         #=> ["1", "2", "", "3", "4"]
"1,2,,3,4,,".split(',', 4)      #=> ["1", "2", "", "3,4,,"]
6.字符串替换
1
2
3
4
5
str.gsub(pattern, replacement) => new_str
str.gsub(pattern) {|match| block } => new_str
"hello".gsub(/[aeiou]/, '*')              #=> "h*ll*"     #将元音替换成*号
"hello".gsub(/([aeiou])/, '<\1>')         #=> "h<e>ll<o>"   #将元音加上尖括号,\1表示保留原有字符???
"hello".gsub(/./) {|s| s[0].to_s + ' '}   #=> "104 101 108 108 111 "

ruby中带“!“和不带”!“的方法的最大的区别就是带”!"的会改变调用对象本身了。比方说str.gsub(/a/, ‘b’),不会改变str本身,只会返回一个新的str。而str.gsub!(/a/, ‘b’)就会把str本身给改了。
但是gsub和gsub!还有另外一个不同点就是,gsub不管怎么样都会返回一个新的字符串,而gsub!只有在有字符被替换的情况下才会返回一个新的字符串,假如说没有任何字符被替换,gsub!只会返回nil.

字符串替换二:
1
2
3
str.replace(other_str) => str
s = "hello"         #=> "hello"
s.replace "world"   #=> "world"
7.字符串删除:
1
2
3
4
5
str.delete([other_str]+) => new_str
"hello".delete "l","lo"        #=> "heo"
"hello".delete "lo"            #=> "he"
"hello".delete "aeiou", "^e"   #=> "hell"
"hello".delete "ej-m"          #=> "ho"
8.去掉前和后的空格
1
2
3
str.lstrip => new_str
" hello ".lstrip   #=> "hello "
"hello".lstrip       #=> "hello"
9.字符串匹配
1
str.match(pattern) => matchdata or nil
10.字符串反转
1
2
str.reverse => new_str
"stressed".reverse   #=> "desserts"
11.去掉重复的字符
1
2
3
4
str.squeeze([other_str]*) => new_str
"yellow moon".squeeze                  #=> "yelow mon" #默认去掉串中所有重复的字符
" now   is the".squeeze(" ")         #=> " now is the" #去掉串中重复的空格
"putters shoot balls".squeeze("m-z")   #=> "puters shot balls" #去掉指定范围内的重复字符
12.转化成数字
1
2
str.to_i=> str
"12345".to_i             #=> 12345

ruby基础

Find

http://ruby-doc.org/stdlib-1.9.3/libdoc/find/rdoc/Find.html

1
2
3
4
5
6
7
8
9
10
11
12
13
require 'find'
total_size = 0
Find.find(ENV["HOME"]) do |path|
  if FileTest.directory?(path)
    if File.basename(path)[0] == ?.
      Find.prune       # Don't look any further into this directory.
    else
      next
    end
  else
    total_size += FileTest.size(path)
  end
end

Time

1
2
3
4
p Time.parse(“2002-03-17”)       #=> Sun Mar 17 00:00:00 +0800[v2] 2002
p Time.now        # =>Mon Oct 20 06:02:10 JST 2003
p Time.now.to_a      # => [10, 2, 6, 20, 10, 2003, 1, 293,false, "JST"]
p Time.now.to_f      # => 1418540681.0154862

liquid用法笔记

原文

  • 注意本文代码中的 { {,{ %,% },} },{ { {,} } } 中间的空格都要去掉才能执行

在折腾github上博客的时候, 遇到一些jekyll, 正确来说应该是Liquid用法的问题。 于是一系列搜索之后终于找到了比较容易理解的文档>>

关于Liquid的语法使用,看完一遍,就能愉快的在github上继续折腾博客了。有些看不大懂,没翻译,都是自己的见解,有些根本用不上就不解释了。

Liquid有两种标记类型: Output 和 Tag.

Output标记,用于输出文本,格式采用 { { 两个尖括号包围 } }
Tag标记,用于执行命令或者处理 格式: { % 一对尖括号内一对百分号 % }

我的见解是: 类比jsp格式, Output相当于 <%=variable>,即输出变量值;
Tag相当于<% int i=2 ;%>,一种数据处理,但不做输出效果.

Output

例子:

1
2
3
Hello { {name} }
Hello { {user.name} }
Hello { { 'tobi' } }
高级Output: Filters//过滤器

Filters过滤器,数据处理的操作方法.
过滤器的第一个参数,往往是过滤器运算符'|‘左边的Output,而过滤器的返回值,是通过过滤运算符右边的操作所得到的,过滤器可以叠加操作,最终得到该Output所要输出的值。(这段我见解,翻译不过来 = =)
如下:

1
2
3
Hello { { 'tobi' | upcase } }
Hello tobi has { { 'tobi' | size } } letters!
Hello { { 'now' | date: "%Y %h" } }
标准过滤器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
date - 格式化时间
capitalize - 输出字符串,字符串(句子)首字母大写 e.g. 假设tb为"hello world"{ { tb|capitalize } } #=> 'Hello world'
downcase - 转换小写
upcase - 转换大写
first - 获取数组的第一个元素
last - 获取数组的最后一个元素
join - 用指定的字符拼接数组元素
sort - 排序数组
map - map/collect an array on a given property
size - 返回数组大小
escape - 转移字符串
escape_once - returns an escaped version of html without affecting existing escaped entities
strip_html - 除去字符串中的html标签?
strip_newlines - 除去字符串中的回车?
newline_to_br - 将所有的回车"\n" 转换成"<br />"?
replace - 替换所有匹配内容 e.g.{ { 'forfor' | replace:'for', 'bar' } } #=> 'barbar'
replace_first - 替换第一个匹配内容 e.g.{ { 'forfor' | replace_first:'for', 'bar' } } #=> 'barfor'
remove - 移除所有匹配内容 e.g.{ { 'forbarforbar' | remove:'for'} } #=> 'barbar'
remove_first - 移除第一个匹配内容 e.g.{ { 'forbarforbar' | remove_first:'for'} } #=> 'barforbar'
truncate - truncate a string down to x characters
truncatewords - truncate a string down to x words
prepend - 在字符串前面加上内容 e.g.{ {'bar'|prepend:'far'} } #=> 'farbar'
append - 字符串后面加上内容 e.g.{ {'bar'|append: 'foo'} }#=> 'barfoo'
minus - 减法 e.g. { {4|minus:2} } #=>2
plus - 加法 e.g. { { 4|plus:2} } #=> 6
times - 乘法 e.g. { {10|times:2} } #=> 20
divided_by - 除法 e.g. { { 10 | divided_by:2} } #=> 5
split - 分割字符串 e.g.{ { "a~b" | split:'~'} } #=> ['a','b']
modulo - 取余 e.g. { { 3 | modulo:2 } } #=> 1

Tags

Tag在模板中起到处理逻辑的作用。
下面是目前支持的Tag:

1
2
3
4
5
6
7
8
9
10
assign - 定义变量 e.g. { % assign tt = 1 % } 定义了变量tt数值为1
capture - Block tag为变量赋值 e.g.{ % capture dont % }{ { tt } }{ % endcapture % } 将tt的值赋给 dont
case - Block tag its the standard case...when block
comment - Block tag 注释
cycle - Cycle is usually used within a loop to alternate between values, like colors or DOM classes.
for - for循环block
if - 判断block
include - 引入模板
raw - 转义内容tag e.g.{ % raw % }{ { this } }{ % endraw% } #=> '{ { this } }'
unless - Mirror of if statement
Comments

注释隐藏

1
2
We made 1 million dollars { % comment % } in losses { % endcomment % } this year
Raw

当包裹内容出现冲突语法时,不会执行其处理。

1
2
3
{ % raw % }
  In Handlebars, { { this } } will be HTML-escaped, but { { { that } } } will not.
{ % endraw % }
if/else

e.g.

1
2
3
{ % if user % }
  Hello { { user.name } }
{ % endif % }
1
2
3
4
# Same as above
{ % if user != null % }
  Hello { { user.name } }
{ % endif % }
1
2
3
{ % if user.name != 'tobi' % }
  Hello non-tobi
{ % endif % }
1
2
3
4
# Same as above
{ % unless user.name == 'tobi' % }
  Hello non-tobi
{ % endunless % }
1
2
3
{ % if user.payments.size > 0  % }
   you paid !
{ % endif % }
Case Statement

多条件

1
2
3
4
5
6
7
8
{ % case condition % }
{ % when 1 % }
hit 1
{ % when 2 or 3 % }
hit 2 or 3
{ % else % }
... else ...
{ % endcase % }
1
2
3
4
5
6
7
8
9
{ % case template % }

{ % when 'label' % }
	 // { { label.title } }
{ % when 'product' % }
	 // { { product.vendor | link_to_vendor } } / { { product.title } }
{ % else % }
	 // { {page_title} }
{ % endcase % }
Cycle

循环列举

1
2
3
4
{ % cycle 'one', 'two', 'three' % }
{ % cycle 'one', 'two', 'three' % }
{ % cycle 'one', 'two', 'three' % }
{ % cycle 'one', 'two', 'three' % }

结果:

1
2
3
4
one
two
three
one

可以通过命名分组:

1
2
3
4
{ % cycle 'group 1': 'one', 'two', 'three' % }
{ % cycle 'group 1': 'one', 'two', 'three' % }
{ % cycle 'group 2': 'one', 'two', 'three' % }
{ % cycle 'group 2': 'one', 'two', 'three' % }

结果:

1
2
3
4
one
two
one
two
for 循环

循环集合:

1
2
3
{ % for item in array % }
  { { item } }
{ % endfor % }

遍历hash时:item[0]包含键,item[1]包含值

1
2
3
{ % for item in hash % }
  { { item[0] } }: { { item[1] } }
{ % endfor % }

for循环时,下列变量可以辅助使用:

1
2
3
4
5
6
7
forloop.length      # => length of the entire for loop
forloop.index       # => index of the current iteration
forloop.index0      # => index of the current iteration (zero based)
forloop.rindex      # => how many items are still left?
forloop.rindex0     # => how many items are still left? (zero based)
forloop.first       # => is this the first iteration?
forloop.last        # => is this the last iteration?

还有一些变量可以用来处理循环时选择性处理:
limit:int - 限制遍历个数
offset:int - 从第n个数开始遍历

1
2
3
4
5
# array = [1,2,3,4,5,6]
{ % for item in array limit:2 offset:2 % }
  { { item } }
{ % endfor % }
# results in 3,4

反序遍历:

1
2
3
{ % for item in collection reversed % } 
{ {item} } 
{ % endfor % }

除了遍历集合,还可以定义一个范围的数字来遍历:

1
2
3
4
5
# if item.quantity is 4...
{ % for i in (1..item.quantity) % }
  { { i } }
{ % endfor % }
# results in 1,2,3,4
变量赋值

赋值变量:

1
2
3
4
5
{ % assign name = 'freestyle' % }

{ % for t in collections.tags % }{ % if t == name % }
  <p>Freestyle!</p>
{ % endif % }{ % endfor % }

还可以赋值布尔值:

1
2
3
4
5
6
7
8
9
{ % assign freestyle = false % }

{ % for t in collections.tags % }{ % if t == 'freestyle' % }
  { % assign freestyle = true % }
{ % endif % }{ % endfor % }

{ % if freestyle % }
  <p>Freestyle!</p>
{ % endif % }

赋值处理过的数据:可以用capture

1
2
3
4
5
6
7
8
{ % capture attribute_name % }{ { item.title | handleize } }-{ { i } }-color{ % endcapture % }

  <label for="{ { attribute_name } }">Color:</label>
  <select name="attributes[{ { attribute_name } }]" id="{ { attribute_name } }">
	<option value="red">Red</option>
	<option value="green">Green</option>
	<option value="blue">Blue</option>
  </select>