review

  书中 很多 地方 新的内核 除了壳子 都面目全非了, 研究内核就是痛苦终身的事情  。如果你订阅了mail list  那你肯定坚持不了一个月就 unsubscribe了  。 

 

 上层 recv send 二十年如一日 的调用  kernel 里面早就翻天覆地了 从 2.6.38的内核看来吧  

 

 以前看书从来不写blog , 现在发现写 还是有好处的 , 比如一年前如果我写了cglib  jvm 的阅读心得 ,我现在就不会忘记的差不多了 , 现在看别人讨论spring 源码都觉得 陌生的可怕 。。。唉 

 

 因为是  review 所以只是一些 个人的 记录 。 不是 全书的读书笔记 。

 

 

================================================

 

Notification chains

 

 

通知链: 当一个给定事件发生了 要执行的一系列简单的函数 ,每一个函数让另一个子系统知道有情况发生了所以有一个被通知的 和通知者(Observer 模式...)

 

函数的执行完全靠 被通知方的意愿执行 通知方不能干涉  它只能定义一个通知链,

任何内核子系统 都可以把在这个通知链表上  注册自己需要的回调 函数 。

 

通知链的好处就不多说了 ,自己去看Observer 模式 .....

 

  

每一个内核的子系统维护组织 都不需要天天盯着邮件列表看看有没有新的子系统加入 。 

他们只需要  : 

 

这个子系统有什么有趣的事情 他想知道的 。

他想知道别的子系统对这个事件感兴趣不。 所以现在事情大家都可以共享  但都可以解放不去管别人了

 

Notifier.h 里面定了  它 的结构 

 

 

通知链分 4种 类型 

 * Atomic notifier chains: Chain callbacks run in interrupt/atomic

 * context. Callouts are not allowed to block.

 * Blocking notifier chains: Chain callbacks run in process context.

 * Callouts are allowed to block.

 * Raw notifier chains: There are no restrictions on callbacks,

 * registration, or unregistration.  All locking and protection

 * must be provided by the caller.

 * SRCU notifier chains: A variant of blocking notifier chains, with

 * the same restrictions.

 

举例 :

 写道
struct notifier_block {
  int (*notifier_call)(struct notifier_block *, unsigned long, void *);
  struct notifier_block *next;
  int priority;
};
 

 

 

 

 

 

 

 

 

通知产生通过  notifier_call_chain  这个函数  也是在 Notifier.c 中 

 

static int __kprobes notifier_call_chain(struct notifier_block **nl,
					unsigned long val, void *v,
					int nr_to_call,	int *nr_calls)
{
	int ret = NOTIFY_DONE;
	struct notifier_block *nb, *next_nb;
    /*在一个安全的情况下获得rcu 保护的指针 */
	nb = rcu_dereference_raw(*nl);

	while (nb && nr_to_call) {
		next_nb = rcu_dereference_raw(nb->next);
		ret = nb->notifier_call(nb, val, v);

		if (nr_calls)
			(*nr_calls)++;

		if ((ret & NOTIFY_STOP_MASK) == NOTIFY_STOP_MASK)
			break;
		nb = next_nb;
		nr_to_call--;
	}
	return ret;
}

 

 

 

 

 

 

System Initializaion 

 

 

 

首先  Main.c 中 的 

 写道
asmlinkage void __init start_kernel(void)
static noinline void __init_refok rest_init(void) __releases(kernel_lock)
kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);
static void __init do_basic_setup(void)
static void __init do_initcalls(void)
{
initcall_t *fn;
for (fn = __early_initcall_end; fn < __initcall_end; fn++)
do_one_initcall(*fn);
/* Make sure there is no pending stuff from the initcall sequence */
flush_scheduled_work();
}
init_post();

 

 

 

注册和初始化任务 一部分是由内核完成的 ,另一部分是设备驱动里面做的 。

 

主要分为 

 

硬件初始化:  设备驱动做的, 比如初始化IRQ line  和I/O 端口映射 内存映射 DMA(dam9000)之类   的(request_region release_region等一些请求资源API可以去看设备驱动的书 

 

 

软件初始化: 根据编译内核的config 选项 还有一些别的配置文件决定 协议啊  功能啊什么的

 

 

内核与驱动之间的交互 主要是 

轮询  中断 (类比SNMP 中的  Get/Trap)

 

算了 驱动的东西不写了, 看datasheet CS8900的驱动吧  写的话下去远了

不想看懂驱动源码的 记得  文件系统永远是你的天堂 驱动对外的接口

/sys/module/网卡驱动名/parameters

/sys/class/net/eth0

static int __init net_dev_init(void)
{
	int i, rc = -ENOMEM;
./*proc 文件系统和 kobject 设备模型的初始化 */
	if (dev_proc_init())
		goto out;

	if (netdev_kobject_init())
		goto out;

	INIT_LIST_HEAD(&ptype_all);
	/*初始化支持的协议数组*/
	for (i = 0; i < PTYPE_HASH_SIZE; i++)
		INIT_LIST_HEAD(&ptype_base[i]);
	/*注册网络子系统 ,当网络命名空间被创建时就会去回调 传入结构的init方法 etc*/
	if (register_pernet_subsys(&netdev_net_ops))
		goto out;

	/*初始化所有cpu上面的包接收队列*/
	for_each_possible_cpu(i) {
		struct softnet_data *sd = &per_cpu(softnet_data, i);
	/*2.6.38里面这个结构变的十分强大*/
		memset(sd, 0, sizeof(*sd));
		skb_queue_head_init(&sd->input_pkt_queue);
		skb_queue_head_init(&sd->process_queue);
		sd->completion_queue = NULL;
		INIT_LIST_HEAD(&sd->poll_list);
		sd->output_queue = NULL;
		sd->output_queue_tailp = &sd->output_queue;
/*对于支持RPS的配置 ,将会被多个CPU来使用
对于.38内核RPS(XPS)的实现以后说 <sys fs 依然给了你配置的能力>
 /sys/class/net/<device>/queues/tx-<n>/xps_cpus 
 /sys/class/net/<device>/queues/rx-<n>/rps_cpus*/
#ifdef CONFIG_RPS
		sd->csd.func = rps_trigger_softirq;
		sd->csd.info = sd;
		sd->csd.flags = 0;
		sd->cpu = i;
#endif

		sd->backlog.poll = process_backlog;
		sd->backlog.weight = weight_p;
		sd->backlog.gro_list = NULL;
		sd->backlog.gro_count = 0;
	}

	dev_boot_phase = 0;

	/*注册一个 loopback <包括proc fs> 和default 设备*/
	if (register_pernet_device(&loopback_net_ops))
		goto out;

	if (register_pernet_device(&default_device_ops))
		goto out;
	/*使能TX RX软中断*/
	open_softirq(NET_TX_SOFTIRQ, net_tx_action);
	open_softirq(NET_RX_SOFTIRQ, net_rx_action);
	
	hotcpu_notifier(dev_cpu_callback, 0);	/*初始化DST 子系统 通知链 */
	dst_init();
	/*用于 IP multicast的每个网络设备值  proc/net/dev_mcast*/
	dev_mcast_init();
	rc = 0;
out:
	return rc;
}

 

 

 

 

static int __init net_dev_init(void) 用了gcc __section(.init.text) boot 的时候还只有一个线程什么同步都不需要

 

下面是精简的主要代码 (from 2.6.38)


 

有时候  内核也需要执行 PATH=/sbin:/usr/sbin:/bin:/usr/bin 下面的命令...

 

也有类似  execpl 的 函数 call_usermodehelper  当然也有wrapper 过的

 request_module  kobject_hotplug

/sbin/modprobe and /sbin/hotplug

 

 

 

 

你可能感兴趣的:(spring,.net,linux,网络协议,读书)