﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-beautykingdom-随笔分类-linux kernel</title><link>http://www.cppblog.com/beautykingdom/category/12530.html</link><description /><language>zh-cn</language><lastBuildDate>Tue, 13 Sep 2011 16:44:03 GMT</lastBuildDate><pubDate>Tue, 13 Sep 2011 16:44:03 GMT</pubDate><ttl>60</ttl><item><title>ubuntu下编译内核</title><link>http://www.cppblog.com/beautykingdom/archive/2011/09/14/155714.html</link><dc:creator>chatler</dc:creator><author>chatler</author><pubDate>Tue, 13 Sep 2011 16:02:00 GMT</pubDate><guid>http://www.cppblog.com/beautykingdom/archive/2011/09/14/155714.html</guid><wfw:comment>http://www.cppblog.com/beautykingdom/comments/155714.html</wfw:comment><comments>http://www.cppblog.com/beautykingdom/archive/2011/09/14/155714.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/beautykingdom/comments/commentRss/155714.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/beautykingdom/services/trackbacks/155714.html</trackback:ping><description><![CDATA[<div>先make menuconfig，选定cpu型号，要不会在install内核并重启的时候出现cpu unsupported之类的错。具体的命令为：<br /><span style="widows: 2; text-transform: none; background-color: rgb(250,250,250); text-indent: 0px; letter-spacing: normal; font: 12px/16px Monaco, 'Courier New', monospace; white-space: normal; orphans: 2; color: rgb(0,102,0); word-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" class="Apple-style-span">sudo make-kpkg&nbsp;--initrd --append-to-version=dell1400 kernel_image kernel-headers<br /><span style="widows: 2; text-transform: none; background-color: rgb(250,250,250); text-indent: 0px; letter-spacing: normal; font: 12px/16px Monaco, 'Courier New', monospace; white-space: normal; orphans: 2; color: rgb(0,102,0); word-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" class="Apple-style-span">sudo dpkg -i&nbsp; &nbsp;linux-image-*.deb<br /><br /><br />references:<br />1.<a href="http://forum.ubuntu.org.cn/viewtopic.php?t=134404">http://forum.ubuntu.org.cn/viewtopic.php?t=134404</a></span></span></div><img src ="http://www.cppblog.com/beautykingdom/aggbug/155714.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/beautykingdom/" target="_blank">chatler</a> 2011-09-14 00:02 <a href="http://www.cppblog.com/beautykingdom/archive/2011/09/14/155714.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>&lt;转&gt;how to start a kernel thread</title><link>http://www.cppblog.com/beautykingdom/archive/2011/03/22/142512.html</link><dc:creator>chatler</dc:creator><author>chatler</author><pubDate>Tue, 22 Mar 2011 13:08:00 GMT</pubDate><guid>http://www.cppblog.com/beautykingdom/archive/2011/03/22/142512.html</guid><wfw:comment>http://www.cppblog.com/beautykingdom/comments/142512.html</wfw:comment><comments>http://www.cppblog.com/beautykingdom/archive/2011/03/22/142512.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/beautykingdom/comments/commentRss/142512.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/beautykingdom/services/trackbacks/142512.html</trackback:ping><description><![CDATA[<span style="WIDOWS: 2; TEXT-TRANSFORM: none; TEXT-INDENT: 0px; BORDER-COLLAPSE: separate; FONT: medium 'Times New Roman'; WHITE-SPACE: normal; ORPHANS: 2; LETTER-SPACING: normal; COLOR: rgb(0,0,0); WORD-SPACING: 0px; -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" class=Apple-style-span><span style="FONT-FAMILY: verdana, arial, sans-serif; FONT-SIZE: 13px; -webkit-border-horizontal-spacing: 1px; -webkit-border-vertical-spacing: 1px" class=Apple-style-span>Linux Kernel Threads in Device Drivers<span class=Apple-converted-space>&nbsp;</span><br>Purpose<span class=Apple-converted-space>&nbsp;</span><br>This examples shows how to create and stop a kernel thread.<span class=Apple-converted-space>&nbsp;</span><br>The driver is implemented as a loadable module. In the init_module() routine five kernel threads are created. This kernel threads sleep one second, wake up, print a message and fall asleep again. On unload of the module (cleanup_module), the kernel threads are killed.<span class=Apple-converted-space>&nbsp;</span><br>The example has been tested with Linux kernel 2.4.2 on Intel (uni processor only) and Alpha platform (COMPAQ Personal Workstation 500au (uni processor), DS20 and ES40 (SMP).<span class=Apple-converted-space>&nbsp;</span><br>A version for the 2.2 kernel can be found here. Note: depending on the context of the creator of the threads the new threads may inherit properties from the parent you do not want to have. The new version avoids this by having keventd create the threads. The 2.2. kernel do not have a keventd, so this approach is not implementable there.<span class=Apple-converted-space>&nbsp;</span><br><br>Functions in example<span class=Apple-converted-space>&nbsp;</span><br>start_kthread: creates a new kernel thread. Can be called from any process context but not from interrupt. The functions blocks until the thread started.<span class=Apple-converted-space>&nbsp;</span><br>stop_kthread: stop the thread. Can be called from any process context but the thread to be terminated. Cannot be called from interrupt context. The function blocks until the thread terminated.<span class=Apple-converted-space>&nbsp;</span><br>init_kthread: sets the environment of the new threads. Is to be called out of the created thread.<span class=Apple-converted-space>&nbsp;</span><br>exit_kthread: needs to be called by the thread to be terminated on exit<span class=Apple-converted-space>&nbsp;</span><br>Creation of new Thread<span class=Apple-converted-space>&nbsp;</span><br>A new thread is created with kernel_thread(). The thread inherits properties from its parents. To make sure that we do not get any weired properties, we let keventd create the new thread.<span class=Apple-converted-space>&nbsp;</span><br>The new thread is created with start_kthread(). It uses a semaphore to block until the new thread is running. A down() blocks the start_kthread() routine until the corresponding up() call in init_kthread() is executed.<span class=Apple-converted-space>&nbsp;</span><br>The new thread must call init_kthread() in order to let the creator continue.<span class=Apple-converted-space>&nbsp;</span><br>Stop of new Thread<span class=Apple-converted-space>&nbsp;</span><br>stop_kthread() sets a flag that the thread uses to determine whether do die or not and sends a SIGKILL to the thread. This signal causes the thread to be woken up. On wakeup it will check for the flag and then terminate itself by calling exit_kthread and returning from the thread function. With a semaphore the stop_kthread() function blocks until the thread terminated.<span class=Apple-converted-space>&nbsp;</span><br>Initialization of new Thread<span class=Apple-converted-space>&nbsp;</span><br>Within the new created thread, init_kthread() needs to be called. This function sets a signal mask, initialises a wait queue, the termination flag and sets a new name for the thread. With a up() call it notifies the creator that the setup is done.<span class=Apple-converted-space>&nbsp;</span><br>Exit of new Thread<span class=Apple-converted-space>&nbsp;</span><br>When the thread receives the notification to terminate itself, is calls the exit_kthread() function. It notifies the stop_kthread() function that it terminated with an up() call.<span class=Apple-converted-space>&nbsp;</span><br>The new Thread itself<span class=Apple-converted-space>&nbsp;</span><br>The new thread is implemented in the example_thread() function. It runs an endless loop (for(;;)). In the loop it falls asleep with the interruptible_sleep_on_timeout() function. It comes out of this function either when the timeout expires or when a signal got caught.<span class=Apple-converted-space>&nbsp;</span><br>The "work" in the thread is to print out a message with printk.<span class=Apple-converted-space>&nbsp;</span><br>Kernel Versions<span class=Apple-converted-space>&nbsp;</span><br>The example has been tested on 2.4.2.<span class=Apple-converted-space>&nbsp;</span><br>Example Device Driver Code<span class=Apple-converted-space>&nbsp;</span><br>The example consists of four files: kthread.h, kthread.c, thread_drv.c and a Makefile<span class=Apple-converted-space>&nbsp;</span><br>kthread.h<span class=Apple-converted-space>&nbsp;</span><br>#ifndef _KTHREAD_H<span class=Apple-converted-space>&nbsp;</span><br>#define _KTHREAD_H<span class=Apple-converted-space>&nbsp;</span><br>#include &lt;linux/config.h&gt;<span class=Apple-converted-space>&nbsp;</span><br>#include &lt;linux/version.h&gt;<span class=Apple-converted-space>&nbsp;</span><br><br>#include &lt;linux/kernel.h&gt;<span class=Apple-converted-space>&nbsp;</span><br>#include &lt;linux/sched.h&gt;<span class=Apple-converted-space>&nbsp;</span><br>#include &lt;linux/tqueue.h&gt;<span class=Apple-converted-space>&nbsp;</span><br>#include &lt;linux/wait.h&gt;<span class=Apple-converted-space>&nbsp;</span><br><br>#include &lt;asm/unistd.h&gt;<span class=Apple-converted-space>&nbsp;</span><br>#include &lt;asm/semaphore.h&gt;<span class=Apple-converted-space>&nbsp;</span><br><br>/* a structure to store all information we need<span class=Apple-converted-space>&nbsp;</span><br>for our thread */<span class=Apple-converted-space>&nbsp;</span><br>typedef struct kthread_struct<span class=Apple-converted-space>&nbsp;</span><br>{<span class=Apple-converted-space>&nbsp;</span><br>/* private data */<span class=Apple-converted-space>&nbsp;</span><br><br>/* Linux task structure of thread */<span class=Apple-converted-space>&nbsp;</span><br>struct task_struct *thread;<span class=Apple-converted-space>&nbsp;</span><br>/* Task queue need to launch thread */<span class=Apple-converted-space>&nbsp;</span><br>struct tq_struct tq;<span class=Apple-converted-space>&nbsp;</span><br>/* function to be started as thread */<span class=Apple-converted-space>&nbsp;</span><br>void (*function) (struct kthread_struct *kthread);<span class=Apple-converted-space>&nbsp;</span><br>/* semaphore needed on start and creation of thread. */<span class=Apple-converted-space>&nbsp;</span><br>struct semaphore startstop_sem;<span class=Apple-converted-space>&nbsp;</span><br><br>/* public data */<span class=Apple-converted-space>&nbsp;</span><br><br>/* queue thread is waiting on. Gets initialized by<span class=Apple-converted-space>&nbsp;</span><br>init_kthread, can be used by thread itself.<span class=Apple-converted-space>&nbsp;</span><br>*/<span class=Apple-converted-space>&nbsp;</span><br>wait_queue_head_t queue;<span class=Apple-converted-space>&nbsp;</span><br>/* flag to tell thread whether to die or not.<span class=Apple-converted-space>&nbsp;</span><br>When the thread receives a signal, it must check<span class=Apple-converted-space>&nbsp;</span><br>the value of terminate and call exit_kthread and terminate<span class=Apple-converted-space>&nbsp;</span><br>if set.<span class=Apple-converted-space>&nbsp;</span><br>*/<span class=Apple-converted-space>&nbsp;</span><br>int terminate;<span class=Apple-converted-space>&nbsp;</span><br>/* additional data to pass to kernel thread */<span class=Apple-converted-space>&nbsp;</span><br>void *arg;<span class=Apple-converted-space>&nbsp;</span><br>} kthread_t;<span class=Apple-converted-space>&nbsp;</span><br><br>/* prototypes */<span class=Apple-converted-space>&nbsp;</span><br><br>/* start new kthread (called by creator) */<span class=Apple-converted-space>&nbsp;</span><br>void start_kthread(void (*func)(kthread_t *), kthread_t *kthread);<span class=Apple-converted-space>&nbsp;</span><br><br>/* stop a running thread (called by "killer") */<span class=Apple-converted-space>&nbsp;</span><br>void stop_kthread(kthread_t *kthread);<span class=Apple-converted-space>&nbsp;</span><br><br>/* setup thread environment (called by new thread) */<span class=Apple-converted-space>&nbsp;</span><br>void init_kthread(kthread_t *kthread, char *name);<span class=Apple-converted-space>&nbsp;</span><br><br>/* cleanup thread environment (called by thread upon receiving termination signal) */<span class=Apple-converted-space>&nbsp;</span><br>void exit_kthread(kthread_t *kthread);<span class=Apple-converted-space>&nbsp;</span><br><br>#endif<span class=Apple-converted-space>&nbsp;</span><br><br>kthread.c<span class=Apple-converted-space>&nbsp;</span><br>#include &lt;linux/config.h&gt;<span class=Apple-converted-space>&nbsp;</span><br>#include &lt;linux/version.h&gt;<span class=Apple-converted-space>&nbsp;</span><br><br>#if defined(MODVERSIONS)<span class=Apple-converted-space>&nbsp;</span><br>#include &lt;linux/modversions.h&gt;<span class=Apple-converted-space>&nbsp;</span><br>#endif<span class=Apple-converted-space>&nbsp;</span><br>#include &lt;linux/kernel.h&gt;<span class=Apple-converted-space>&nbsp;</span><br>#include &lt;linux/sched.h&gt;<span class=Apple-converted-space>&nbsp;</span><br>#include &lt;linux/tqueue.h&gt;<span class=Apple-converted-space>&nbsp;</span><br>#include &lt;linux/wait.h&gt;<span class=Apple-converted-space>&nbsp;</span><br>#include &lt;linux/signal.h&gt;<span class=Apple-converted-space>&nbsp;</span><br><br>#include &lt;asm/semaphore.h&gt;<span class=Apple-converted-space>&nbsp;</span><br>#include &lt;asm/smplock.h&gt;<span class=Apple-converted-space>&nbsp;</span><br><br>#include "kthread.h"<span class=Apple-converted-space>&nbsp;</span><br><br>/* private functions */<span class=Apple-converted-space>&nbsp;</span><br>static void kthread_launcher(void *data)<span class=Apple-converted-space>&nbsp;</span><br>{<span class=Apple-converted-space>&nbsp;</span><br>kthread_t *kthread = data;<span class=Apple-converted-space>&nbsp;</span><br>kernel_thread((int (*)(void *))kthread-&gt;function, (void *)kthread, 0);<span class=Apple-converted-space>&nbsp;</span><br><br>}<span class=Apple-converted-space>&nbsp;</span><br><br>/* public functions */<span class=Apple-converted-space>&nbsp;</span><br><br>/* create a new kernel thread. Called by the creator. */<span class=Apple-converted-space>&nbsp;</span><br>void start_kthread(void (*func)(kthread_t *), kthread_t *kthread)<span class=Apple-converted-space>&nbsp;</span><br>{<span class=Apple-converted-space>&nbsp;</span><br>/* initialize the semaphore:<span class=Apple-converted-space>&nbsp;</span><br>we start with the semaphore locked. The new kernel<span class=Apple-converted-space>&nbsp;</span><br>thread will setup its stuff and unlock it. This<span class=Apple-converted-space>&nbsp;</span><br>control flow (the one that creates the thread) blocks<span class=Apple-converted-space>&nbsp;</span><br>in the down operation below until the thread has reached<span class=Apple-converted-space>&nbsp;</span><br>the up() operation.<span class=Apple-converted-space>&nbsp;</span><br>*/<span class=Apple-converted-space>&nbsp;</span><br>init_MUTEX_LOCKED(&amp;kthread-&gt;startstop_sem);<span class=Apple-converted-space>&nbsp;</span><br><br>/* store the function to be executed in the data passed to<span class=Apple-converted-space>&nbsp;</span><br>the launcher */<span class=Apple-converted-space>&nbsp;</span><br>kthread-&gt;function=func;<span class=Apple-converted-space>&nbsp;</span><br><br>/* create the new thread my running a task through keventd */<span class=Apple-converted-space>&nbsp;</span><br><br>/* initialize the task queue structure */<span class=Apple-converted-space>&nbsp;</span><br>kthread-&gt;tq.sync = 0;<span class=Apple-converted-space>&nbsp;</span><br>INIT_LIST_HEAD(&amp;kthread-&gt;tq.list);<span class=Apple-converted-space>&nbsp;</span><br>kthread-&gt;tq.routine = kthread_launcher;<span class=Apple-converted-space>&nbsp;</span><br>kthread-&gt;tq.data = kthread;<span class=Apple-converted-space>&nbsp;</span><br><br>/* and schedule it for execution */<span class=Apple-converted-space>&nbsp;</span><br>schedule_task(&amp;kthread-&gt;tq);<span class=Apple-converted-space>&nbsp;</span><br><br>/* wait till it has reached the setup_thread routine */<span class=Apple-converted-space>&nbsp;</span><br>down(&amp;kthread-&gt;startstop_sem);<span class=Apple-converted-space>&nbsp;</span><br><br>}<span class=Apple-converted-space>&nbsp;</span><br><br>/* stop a kernel thread. Called by the removing instance */<span class=Apple-converted-space>&nbsp;</span><br>void stop_kthread(kthread_t *kthread)<span class=Apple-converted-space>&nbsp;</span><br>{<span class=Apple-converted-space>&nbsp;</span><br>if (kthread-&gt;thread == NULL)<span class=Apple-converted-space>&nbsp;</span><br>{<span class=Apple-converted-space>&nbsp;</span><br>printk("stop_kthread: killing non existing thread!\n");<span class=Apple-converted-space>&nbsp;</span><br>return;<span class=Apple-converted-space>&nbsp;</span><br>}<span class=Apple-converted-space>&nbsp;</span><br><br>/* this function needs to be protected with the big<span class=Apple-converted-space>&nbsp;</span><br>kernel lock (lock_kernel()). The lock must be<span class=Apple-converted-space>&nbsp;</span><br>grabbed before changing the terminate<span class=Apple-converted-space>&nbsp;</span><br>flag and released after the down() call. */<span class=Apple-converted-space>&nbsp;</span><br>lock_kernel();<span class=Apple-converted-space>&nbsp;</span><br><br>/* initialize the semaphore. We lock it here, the<span class=Apple-converted-space>&nbsp;</span><br>leave_thread call of the thread to be terminated<span class=Apple-converted-space>&nbsp;</span><br>will unlock it. As soon as we see the semaphore<span class=Apple-converted-space>&nbsp;</span><br>unlocked, we know that the thread has exited.<span class=Apple-converted-space>&nbsp;</span><br>*/<span class=Apple-converted-space>&nbsp;</span><br>init_MUTEX_LOCKED(&amp;kthread-&gt;startstop_sem);<span class=Apple-converted-space>&nbsp;</span><br><br>/* We need to do a memory barrier here to be sure that<span class=Apple-converted-space>&nbsp;</span><br>the flags are visible on all CPUs.<span class=Apple-converted-space>&nbsp;</span><br>*/<span class=Apple-converted-space>&nbsp;</span><br>mb();<span class=Apple-converted-space>&nbsp;</span><br><br>/* set flag to request thread termination */<span class=Apple-converted-space>&nbsp;</span><br>kthread-&gt;terminate = 1;<span class=Apple-converted-space>&nbsp;</span><br><br>/* We need to do a memory barrier here to be sure that<span class=Apple-converted-space>&nbsp;</span><br>the flags are visible on all CPUs.<span class=Apple-converted-space>&nbsp;</span><br>*/<span class=Apple-converted-space>&nbsp;</span><br>mb();<span class=Apple-converted-space>&nbsp;</span><br>kill_proc(kthread-&gt;thread-&gt;pid, SIGKILL, 1);<span class=Apple-converted-space>&nbsp;</span><br><br>/* block till thread terminated */<span class=Apple-converted-space>&nbsp;</span><br>down(&amp;kthread-&gt;startstop_sem);<span class=Apple-converted-space>&nbsp;</span><br><br>/* release the big kernel lock */<span class=Apple-converted-space>&nbsp;</span><br>unlock_kernel();<span class=Apple-converted-space>&nbsp;</span><br><br>/* now we are sure the thread is in zombie state. We<span class=Apple-converted-space>&nbsp;</span><br>notify keventd to clean the process up.<span class=Apple-converted-space>&nbsp;</span><br>*/<span class=Apple-converted-space>&nbsp;</span><br>kill_proc(2, SIGCHLD, 1);<span class=Apple-converted-space>&nbsp;</span><br><br>}<span class=Apple-converted-space>&nbsp;</span><br><br>/* initialize new created thread. Called by the new thread. */<span class=Apple-converted-space>&nbsp;</span><br>void init_kthread(kthread_t *kthread, char *name)<span class=Apple-converted-space>&nbsp;</span><br>{<span class=Apple-converted-space>&nbsp;</span><br>/* lock the kernel. A new kernel thread starts without<span class=Apple-converted-space>&nbsp;</span><br>the big kernel lock, regardless of the lock state<span class=Apple-converted-space>&nbsp;</span><br>of the creator (the lock level is *not* inheritated)<span class=Apple-converted-space>&nbsp;</span><br>*/<span class=Apple-converted-space>&nbsp;</span><br>lock_kernel();<span class=Apple-converted-space>&nbsp;</span><br><br>/* fill in thread structure */<span class=Apple-converted-space>&nbsp;</span><br>kthread-&gt;thread = current;<span class=Apple-converted-space>&nbsp;</span><br><br>/* set signal mask to what we want to respond */<span class=Apple-converted-space>&nbsp;</span><br>siginitsetinv(&amp;current-&gt;blocked, sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM));<span class=Apple-converted-space>&nbsp;</span><br><br>/* initialise wait queue */<span class=Apple-converted-space>&nbsp;</span><br>init_waitqueue_head(&amp;kthread-&gt;queue);<span class=Apple-converted-space>&nbsp;</span><br><br>/* initialise termination flag */<span class=Apple-converted-space>&nbsp;</span><br>kthread-&gt;terminate = 0;<span class=Apple-converted-space>&nbsp;</span><br><br>/* set name of this process (max 15 chars + 0 !) */<span class=Apple-converted-space>&nbsp;</span><br>sprintf(current-&gt;comm, name);<span class=Apple-converted-space>&nbsp;</span><br><br>/* let others run */<span class=Apple-converted-space>&nbsp;</span><br>unlock_kernel();<span class=Apple-converted-space>&nbsp;</span><br><br>/* tell the creator that we are ready and let him continue */<span class=Apple-converted-space>&nbsp;</span><br>up(&amp;kthread-&gt;startstop_sem);<span class=Apple-converted-space>&nbsp;</span><br><br>}<span class=Apple-converted-space>&nbsp;</span><br><br>/* cleanup of thread. Called by the exiting thread. */<span class=Apple-converted-space>&nbsp;</span><br>void exit_kthread(kthread_t *kthread)<span class=Apple-converted-space>&nbsp;</span><br>{<span class=Apple-converted-space>&nbsp;</span><br>/* we are terminating */<span class=Apple-converted-space>&nbsp;</span><br><br>/* lock the kernel, the exit will unlock it */<span class=Apple-converted-space>&nbsp;</span><br>lock_kernel();<span class=Apple-converted-space>&nbsp;</span><br>kthread-&gt;thread = NULL;<span class=Apple-converted-space>&nbsp;</span><br>mb();<span class=Apple-converted-space>&nbsp;</span><br><br>/* notify the stop_kthread() routine that we are terminating. */<span class=Apple-converted-space>&nbsp;</span><br>up(&amp;kthread-&gt;startstop_sem);<span class=Apple-converted-space>&nbsp;</span><br>/* the kernel_thread that called clone() does a do_exit here. */<span class=Apple-converted-space>&nbsp;</span><br><br>/* there is no race here between execution of the "killer" and real termination<span class=Apple-converted-space>&nbsp;</span><br>of the thread (race window between up and do_exit), since both the<span class=Apple-converted-space>&nbsp;</span><br>thread and the "killer" function are running with the kernel lock held.<span class=Apple-converted-space>&nbsp;</span><br>The kernel lock will be freed after the thread exited, so the code<span class=Apple-converted-space>&nbsp;</span><br>is really not executed anymore as soon as the unload functions gets<span class=Apple-converted-space>&nbsp;</span><br>the kernel lock back.<span class=Apple-converted-space>&nbsp;</span><br>The init process may not have made the cleanup of the process here,<span class=Apple-converted-space>&nbsp;</span><br>but the cleanup can be done safely with the module unloaded.<span class=Apple-converted-space>&nbsp;</span><br>*/<span class=Apple-converted-space>&nbsp;</span><br><br>}<span class=Apple-converted-space>&nbsp;</span><br><br>thread_drv.c<span class=Apple-converted-space>&nbsp;</span><br>#include &lt;linux/config.h&gt;<span class=Apple-converted-space>&nbsp;</span><br>#include &lt;linux/version.h&gt;<span class=Apple-converted-space>&nbsp;</span><br><br>#include &lt;linux/module.h&gt;<span class=Apple-converted-space>&nbsp;</span><br>#if defined(MODVERSIONS)<span class=Apple-converted-space>&nbsp;</span><br>#include &lt;linux/modversions.h&gt;<span class=Apple-converted-space>&nbsp;</span><br>#endif<span class=Apple-converted-space>&nbsp;</span><br><br>#include &lt;linux/kernel.h&gt;<span class=Apple-converted-space>&nbsp;</span><br>#include &lt;linux/string.h&gt;<span class=Apple-converted-space>&nbsp;</span><br>#include &lt;linux/errno.h&gt;<span class=Apple-converted-space>&nbsp;</span><br>#include &lt;linux/sched.h&gt;<span class=Apple-converted-space>&nbsp;</span><br><br>#include "kthread.h"<span class=Apple-converted-space>&nbsp;</span><br><br>#define NTHREADS 5<span class=Apple-converted-space>&nbsp;</span><br><br>/* the variable that contains the thread data */<span class=Apple-converted-space>&nbsp;</span><br>kthread_t example[NTHREADS];<span class=Apple-converted-space>&nbsp;</span><br><br>/* prototype for the example thread */<span class=Apple-converted-space>&nbsp;</span><br>static void example_thread(kthread_t *kthread);<span class=Apple-converted-space>&nbsp;</span><br><br>/* load the module */<span class=Apple-converted-space>&nbsp;</span><br>int init_module(void)<span class=Apple-converted-space>&nbsp;</span><br>{<span class=Apple-converted-space>&nbsp;</span><br>int i;<span class=Apple-converted-space>&nbsp;</span><br><br>/* create new kernel threads */<span class=Apple-converted-space>&nbsp;</span><br>for (i=0; i &lt;NTHREADS; i++)<span class=Apple-converted-space>&nbsp;</span><br>start_kthread(example_thread, &amp;example<em>);<span class=Apple-converted-space>&nbsp;</span><br><br>return(0);<span class=Apple-converted-space>&nbsp;</span><br>}<span class=Apple-converted-space>&nbsp;</span><br><br>/* remove the module */<span class=Apple-converted-space>&nbsp;</span><br>void cleanup_module(void)<span class=Apple-converted-space>&nbsp;</span><br>{<span class=Apple-converted-space>&nbsp;</span><br>int i;<span class=Apple-converted-space>&nbsp;</span><br><br>/* terminate the kernel threads */<span class=Apple-converted-space>&nbsp;</span><br>for (i=0; i&lt;NTHREADS; i++)<span class=Apple-converted-space>&nbsp;</span><br>stop_kthread(&amp;example);<span class=Apple-converted-space>&nbsp;</span><br><br>return;<span class=Apple-converted-space>&nbsp;</span><br>}<span class=Apple-converted-space>&nbsp;</span><br><br>/* this is the thread function that we are executing */<span class=Apple-converted-space>&nbsp;</span><br>static void example_thread(kthread_t *kthread)<span class=Apple-converted-space>&nbsp;</span><br>{<span class=Apple-converted-space>&nbsp;</span><br>/* setup the thread environment */<span class=Apple-converted-space>&nbsp;</span><br>init_kthread(kthread, "example thread");<span class=Apple-converted-space>&nbsp;</span><br><br>printk("hi, here is the kernel thread\n");<span class=Apple-converted-space>&nbsp;</span><br><br>/* an endless loop in which we are doing our work */<span class=Apple-converted-space>&nbsp;</span><br>for(;;)<span class=Apple-converted-space>&nbsp;</span><br>{<span class=Apple-converted-space>&nbsp;</span><br>/* fall asleep for one second */<span class=Apple-converted-space>&nbsp;</span><br>interruptible_sleep_on_timeout(&amp;kthread-&gt;queue, HZ);<span class=Apple-converted-space>&nbsp;</span><br><br>/* We need to do a memory barrier here to be sure that<span class=Apple-converted-space>&nbsp;</span><br>the flags are visible on all CPUs.<span class=Apple-converted-space>&nbsp;</span><br>*/<span class=Apple-converted-space>&nbsp;</span><br>mb();<span class=Apple-converted-space>&nbsp;</span><br><br>/* here we are back from sleep, either due to the timeout<span class=Apple-converted-space>&nbsp;</span><br>(one second), or because we caught a signal.<span class=Apple-converted-space>&nbsp;</span><br>*/<span class=Apple-converted-space>&nbsp;</span><br>if (kthread-&gt;terminate)<span class=Apple-converted-space>&nbsp;</span><br>{<span class=Apple-converted-space>&nbsp;</span><br>/* we received a request to terminate ourself */<span class=Apple-converted-space>&nbsp;</span><br>break;<span class=Apple-converted-space>&nbsp;</span><br>}<span class=Apple-converted-space>&nbsp;</span><br><br>/* this is normal work to do */<span class=Apple-converted-space>&nbsp;</span><br>printk("example thread: thread woke up\n");<span class=Apple-converted-space>&nbsp;</span><br>}<span class=Apple-converted-space>&nbsp;</span><br>/* here we go only in case of termination of the thread */<span class=Apple-converted-space>&nbsp;</span><br><br>/* cleanup the thread, leave */<span class=Apple-converted-space>&nbsp;</span><br>exit_kthread(kthread);<span class=Apple-converted-space>&nbsp;</span><br><br>/* returning from the thread here calls the exit functions */<span class=Apple-converted-space>&nbsp;</span><br>}<span class=Apple-converted-space>&nbsp;</span><br><br>Makefile<span class=Apple-converted-space>&nbsp;</span><br># set to your kernel tree<span class=Apple-converted-space>&nbsp;</span><br>KERNEL = /usr/src/linux<span class=Apple-converted-space>&nbsp;</span><br><br># get the Linux architecture. Needed to find proper include file for CFLAGS<span class=Apple-converted-space>&nbsp;</span><br>ARCH=$(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)<br># set default flags to compile module<span class=Apple-converted-space>&nbsp;</span><br>CFLAGS = -D__KERNEL__ -DMODULE -I$(KERNEL)/include<span class=Apple-converted-space>&nbsp;</span><br>CFLAGS+= -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing<span class=Apple-converted-space>&nbsp;</span><br><br>all: thread_mod.o<span class=Apple-converted-space>&nbsp;</span><br><br># get configuration of kernel<span class=Apple-converted-space>&nbsp;</span><br>include $(KERNEL)/.config<span class=Apple-converted-space>&nbsp;</span><br># modify CFLAGS with architecture specific flags<span class=Apple-converted-space>&nbsp;</span><br>include $(KERNEL)/arch/${ARCH}/Makefile<span class=Apple-converted-space>&nbsp;</span><br><br># enable the module versions, if configured in kernel source tree<span class=Apple-converted-space>&nbsp;</span><br>ifdef CONFIG_MODVERSIONS<span class=Apple-converted-space>&nbsp;</span><br>CFLAGS+= -DMODVERSIONS -include $(KERNEL)/include/linux/modversions.h<span class=Apple-converted-space>&nbsp;</span><br>endif<span class=Apple-converted-space>&nbsp;</span><br># enable SMP, if configured in kernel source tree<span class=Apple-converted-space>&nbsp;</span><br>ifdef CONFIG_SMP<span class=Apple-converted-space>&nbsp;</span><br>CFLAGS+= -D__SMP__<span class=Apple-converted-space>&nbsp;</span><br>endif<span class=Apple-converted-space>&nbsp;</span><br><br># note: we are compiling the driver object file and then linking<span class=Apple-converted-space>&nbsp;</span><br># we link it into the module. With just one object file as in<span class=Apple-converted-space>&nbsp;</span><br># this example this is not needed. We can just load the object<span class=Apple-converted-space>&nbsp;</span><br># file produced by gcc<span class=Apple-converted-space>&nbsp;</span><br># link the thread driver module<span class=Apple-converted-space>&nbsp;</span><br>thread_mod.o: thread_drv.o kthread.o<span class=Apple-converted-space>&nbsp;</span><br>ld -r -o thread_mod.o thread_drv.o kthread.o<span class=Apple-converted-space>&nbsp;</span><br># compile the kthread object file<span class=Apple-converted-space>&nbsp;</span><br>kthread.o: kthread.c kthread.h<span class=Apple-converted-space>&nbsp;</span><br>gcc $(CFLAGS) -c kthread.c<span class=Apple-converted-space>&nbsp;</span><br># compile the thread driver<span class=Apple-converted-space>&nbsp;</span><br>thread_drv.o: thread_drv.c kthread.h<span class=Apple-converted-space>&nbsp;</span><br>gcc $(CFLAGS) -c thread_drv.c<span class=Apple-converted-space>&nbsp;</span><br><br>clean:<span class=Apple-converted-space>&nbsp;</span><br>rm -f *.o<span class=Apple-converted-space>&nbsp;</span><br><br>Bugs<span class=Apple-converted-space>&nbsp;</span><br>The code assumes that keventd is running with PID 2.<span class=Apple-converted-space>&nbsp;</span><br>Comments, Corrections<span class=Apple-converted-space>&nbsp;</span><br>Please send comments, corrections etc. to the address below.<br><br>from:<br></em><a href="http://www.linuxforum.net/forum/showflat.php?Cat=&amp;Board=linuxK&amp;Number=282973&amp;page=15&amp;view=collapsed&amp;sb=5&amp;o=all"><u><font color=#0000ff size=3 face="Times New Roman">http://www.linuxforum.net/forum/showflat.php?Cat=&amp;Board=linuxK&amp;Number=282973&amp;page=15&amp;view=collapsed&amp;sb=5&amp;o=all</font></u></a><br><br><br></span></span>
<img src ="http://www.cppblog.com/beautykingdom/aggbug/142512.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/beautykingdom/" target="_blank">chatler</a> 2011-03-22 21:08 <a href="http://www.cppblog.com/beautykingdom/archive/2011/03/22/142512.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>The Linux Kernel Module Programming Guide</title><link>http://www.cppblog.com/beautykingdom/archive/2010/11/29/134974.html</link><dc:creator>chatler</dc:creator><author>chatler</author><pubDate>Mon, 29 Nov 2010 04:03:00 GMT</pubDate><guid>http://www.cppblog.com/beautykingdom/archive/2010/11/29/134974.html</guid><wfw:comment>http://www.cppblog.com/beautykingdom/comments/134974.html</wfw:comment><comments>http://www.cppblog.com/beautykingdom/archive/2010/11/29/134974.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/beautykingdom/comments/commentRss/134974.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/beautykingdom/services/trackbacks/134974.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: The Linux Kernel Module Programming GuidePeter Jay SalzmanMichael BurianOri PomerantzCopyright &#169; 2001 Peter Jay Salzman2007-05-18 ver 2.6.4The Linux Kernel Module Programming Guide is a...&nbsp;&nbsp;<a href='http://www.cppblog.com/beautykingdom/archive/2010/11/29/134974.html'>阅读全文</a><img src ="http://www.cppblog.com/beautykingdom/aggbug/134974.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/beautykingdom/" target="_blank">chatler</a> 2010-11-29 12:03 <a href="http://www.cppblog.com/beautykingdom/archive/2010/11/29/134974.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>A Beast of a Different Nature</title><link>http://www.cppblog.com/beautykingdom/archive/2010/05/22/116129.html</link><dc:creator>chatler</dc:creator><author>chatler</author><pubDate>Sat, 22 May 2010 13:09:00 GMT</pubDate><guid>http://www.cppblog.com/beautykingdom/archive/2010/05/22/116129.html</guid><wfw:comment>http://www.cppblog.com/beautykingdom/comments/116129.html</wfw:comment><comments>http://www.cppblog.com/beautykingdom/archive/2010/05/22/116129.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/beautykingdom/comments/commentRss/116129.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/beautykingdom/services/trackbacks/116129.html</trackback:ping><description><![CDATA[<h3 id="412403-994" class="docSection1Title">linux kernel development-chapter 2 getting started with the kernel&nbsp;</h3>
<h3 id="412403-994" class="docSection1Title">A Beast of a Different Nature</h3>
<p>The kernel has several differences compared to normal
user-space applications that, although not making it necessarily harder to
program than user-space, certainly provide unique challenges to kernel
development.<a name="ch02index113"></a>
<p>These differences make the kernel a beast of a different
nature. Some of the usual rules are bent; other rules are entirely new. Although
some of the differences are obvious (we all know the kernel can do anything it
wants), others are not so obvious. The most important of these differences
are</p>
<ul>
    <li>
    <p>The kernel does not have access to the C library.</p>
    </li>
    <li>
    <p>The kernel is coded in GNU C.</p>
    </li>
    <li>
    <p>The kernel lacks memory protection like user-space.</p>
    </li>
    <li>
    <p>The kernel cannot easily use floating point.</p>
    </li>
    <li>
    <p>The kernel has a small fixed-size stack.</p>
    </li>
    <li>
    <p>Because the kernel has asynchronous interrupts, is preemptive,
    and supports SMP, synchronization and concurrency are major concerns within the
    kernel.</p>
    </li>
    <li>
    <p>Portability is important.</p>
    </li>
</ul>
<p>Let's briefly look at each of these issues because all kernel
development must keep them in mind.<a name="ch02index114"></a></p>
<a name="ch02lev2sec6"></a>
<h4 class="docSection2Title">No libc</h4>
<p>Unlike a user-space application, the kernel is not linked
against the standard C library (or any other library, for that matter). There
are multiple reasons for this, including some chicken-and-the-egg situations,
but the primary reason is speed and size. The full C libraryor even a decent
subset of itis too large and too inefficient for the kernel.<a name="ch02index115"></a><a name="ch02index116"></a><a name="ch02index117"></a></p>
<p>Do not fret: Many of the usual libc functions have been
implemented inside the kernel. For example, the common string manipulation
functions are in
<tt>lib/string.c</tt>. Just include
<tt>&lt;linux/string.h&gt;</tt> and have at them.</p>
<a name="ch02sb02"></a>
<p>
<table border="1" cellpadding="5" cellspacing="0" width="90%">
    <tbody>
        <tr>
            <td>
            <h2 class="docSidebarTitle">Header Files</h2>
            <p>When I talk about header files hereor elsewhere in this bookI
            am referring to the kernel header files that are part of the kernel source tree.
            Kernel source files cannot include outside headers, just as they cannot use
            outside libraries.</p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<br>
<p>Of the missing functions, the most familiar is
<tt>printf()</tt>. The kernel does not have access to
<tt>printf()</tt>, but it
does have access to
<tt>printk()</tt>. The
<tt>printk()</tt> function copies the
formatted string into the kernel log buffer, which is normally read by the
syslog program. Usage is similar to
<tt>printf()</tt>:<a name="ch02index118"></a><a name="ch02index119"></a><a name="ch02index120"></a><a name="ch02index121"></a><a name="ch02index122"></a><a name="ch02index123"></a><a name="ch02index124"></a></p>
<pre>printk("Hello world! A string: %s and an integer: %d\n", a_string, an_integer);<br></pre>
<br>
<p>One notable difference between
<tt>printf()</tt> and
<tt>printk()</tt> is that
<tt>printk()</tt> allows you to specify a priority
flag. This flag is used by
<tt>syslogd</tt>(8) to decide where to display kernel
messages. Here is an example of these priorities:<a name="ch02index125"></a><a name="ch02index126"></a><a name="ch02index127"></a></p>
<pre>printk(KERN_ERR "this is an error!\n");<br></pre>
<br>
<p>We will use
<tt>printk()</tt> tHRoughout this book. Later
chapters have more information on
<tt>printk()</tt>.<a name="ch02index128"></a><a name="ch02index129"></a><a name="ch02index130"></a></p>
<a name="ch02lev2sec7"></a>
<h4 class="docSection2Title">GNU C</h4>
<p>Like any self-respecting Unix kernel, the Linux kernel is
programmed in C. Perhaps surprisingly, the kernel is not programmed in strict
ANSI C. Instead, where applicable, the kernel developers make use of various
language extensions available in gcc (the GNU
Compiler Collection, which contains the C compiler used to compile the kernel
and most everything else written in C on a Linux system).<a name="ch02index131"></a><a name="ch02index132"></a><a name="ch02index133"></a><a name="ch02index134"></a></p>
<p>The kernel developers use both ISO C99<sup class="docFootnote"><a class="docLink" href="http://www.cppblog.com/beautykingdom/admin/EditPosts.aspx?opt=1#ch02fn01">[1]</a></sup> and GNU C extensions to the C
language. These changes wed the Linux kernel to gcc, although recently other
compilers, such as the Intel C compiler, have sufficiently supported enough gcc
features that they too can compile the Linux kernel. The ISO C99 extensions that
the kernel uses are nothing special and, because C99 is an official revision of
the C language, are slowly cropping up in a lot of other code. The more
interesting, and perhaps unfamiliar, deviations from standard ANSI C are those
provided by GNU C. Let's look at some of the more interesting extensions that
may show up in kernel code.<a name="ch02index135"></a><a name="ch02index136"></a><a name="ch02index137"></a><a name="ch02index138"></a></p>
<blockquote>
<p><sup><a name="ch02fn01">[1]</a></sup> ISO C99 is the latest
major revision to the ISO C standard. C99 adds numerous enhancements to the
previous major revision, ISO C90, including named structure initializers and a
<tt>complex</tt> type. The latter of which you
cannot use safely from within the kernel.</p>
</blockquote><a name="ch02lev3sec1"></a>
<h5 class="docSection3Title">Inline Functions</h5>
<p>GNU C supports inline functions.
An inline function is, as its name suggests, inserted inline into each function
call site. This eliminates the overhead of function invocation and return
(register saving and restore), and allows for potentially more optimization
because the compiler can optimize the caller and the called function together.
As a downside (nothing in life is free), code size increases because the
contents of the function are copied to all the callers, which increases memory
consumption and instruction cache footprint. Kernel developers use inline
functions for small time-critical functions. Making large functions inline,
especially those that are used more than once or are not time critical, is
frowned upon by the kernel developers.<a name="ch02index139"></a><a name="ch02index140"></a><a name="ch02index141"></a><a name="ch02index142"></a></p>
<p>An inline function is declared when the keywords
<tt>static</tt> and
<tt>inline</tt> are used as part of the function definition.
For example:</p>
<pre>static inline void dog(unsigned long tail_size)<br></pre>
<br>
<p>The function declaration must precede any usage, or else the
compiler cannot make the function inline. Common practice is to place inline
functions in header files. Because they are marked
<tt>static</tt>, an exported
function is not created. If an inline function is used by only one file, it can
instead be placed toward the top of just that file.</p>
<p>In the kernel, using inline functions is preferred over
complicated macros for reasons of type safety.<a name="ch02index143"></a><a name="ch02index144"></a><a name="ch02index145"></a><a name="ch02index146"></a></p>
<a name="ch02lev3sec2"></a>
<h5 class="docSection3Title">Inline Assembly</h5>
<p>The gcc C compiler enables the embedding of assembly
instructions in otherwise normal C functions. This feature, of course, is used
in only those parts of the kernel that are unique to a given system
architecture.<a name="ch02index147"></a><a name="ch02index148"></a><a name="ch02index149"></a><a name="ch02index150"></a></p>
<p>The
<tt>asm()</tt> compiler directive is used to inline
assembly code.</p>
<p>The Linux kernel is programmed in a mixture of C and assembly,
with assembly relegated to low-level architecture and fast path code. The vast
majority of kernel code is programmed in straight C.<a name="ch02index151"></a><a name="ch02index152"></a><a name="ch02index153"></a><a name="ch02index154"></a></p>
<a name="ch02lev3sec3"></a>
<h5 class="docSection3Title">Branch Annotation</h5>
<p>The gcc C compiler has a built-in directive that optimizes
conditional branches as either very likely taken or very unlikely taken. The
compiler uses the directive to appropriately optimize the branch. The kernel
wraps the directive in very easy-to-use macros,
<tt>likely()</tt> and
<tt>unlikely()</tt>.<a name="ch02index155"></a><a name="ch02index156"></a><a name="ch02index157"></a></p>
<p>For example, consider an
<tt>if</tt> statement such as the
following:</p>
<pre>if (foo) {<br>        /* ... */<br>}<br></pre>
<br>
<p>To mark this branch as very unlikely taken (that is, likely not
taken):</p>
<pre>/* we predict foo is nearly always zero ... */<br>if (unlikely(foo)) {<br>        /* ... */<br>}<br></pre>
<br>
<p>Conversely, to mark a branch as very likely taken:</p>
<pre>/* we predict foo is nearly always nonzero ... */<br>if (likely(foo)) {<br>        /* ... */<br>}<br></pre>
<br>
<p>You should only use these directives when the branch direction
is overwhelmingly a known priori or when you want to optimize a specific case at
the cost of the other case. This is an important point: These directives result
in a performance boost when the branch is correctly predicted, but a performance
loss when the branch is mispredicted. A very common usage for
<tt>unlikely()</tt> and
<tt>likely()</tt> is error conditions. As one might
expect,
<tt>unlikely()</tt> finds much more use in the kernel because
<tt>if</tt> statements tend to indicate a special case.<a name="ch02index158"></a><a name="ch02index159"></a><a name="ch02index160"></a></p>
<a name="ch02lev2sec8"></a>
<h4 class="docSection2Title">No Memory Protection</h4>
<p>When a user-space application attempts an illegal memory
access, the kernel can trap the error, send
<tt>SIGSEGV</tt>, and kill the
process. If the kernel attempts an illegal memory access, however, the results
are less controlled. (After all, who is going to look after the kernel?) Memory
violations in the kernel result in an oops, which
is a major kernel error. It should go without saying that you must not illegally
access memory, such as dereferencing a
<tt>NULL</tt> pointerbut within the
kernel, the stakes are much higher!<a name="ch02index161"></a><a name="ch02index162"></a></p>
<p>Additionally, kernel memory is not pageable. Therefore, every
byte of memory you consume is one less byte of available physical memory. Keep
that in mind next time you have to add one more
feature to the kernel!<a name="ch02index163"></a><a name="ch02index164"></a></p>
<a name="ch02lev2sec9"></a>
<h4 class="docSection2Title">No (Easy) Use of Floating Point</h4>
<p>When a user-space process uses floating-point instructions, the
kernel manages the transition from integer to floating point mode. What the
kernel has to do when using floating-point instructions varies by architecture,
but the kernel normally catches a trap and does
something in response.<a name="ch02index165"></a><a name="ch02index166"></a></p>
<p>Unlike user-space, the kernel does not have the luxury of
seamless support for floating point because it cannot trap itself. Using
floating point inside the kernel requires manually saving and restoring the
floating point registers, among possible other chores. The short answer is:
Don't do it; no floating point in the
kernel.</p>
<a name="ch02lev2sec10"></a>
<h4 class="docSection2Title">Small, Fixed-Size Stack</h4>
<p>User-space can get away with statically allocating tons of
variables on the stack, including huge structures and many-element arrays. This
behavior is legal because user-space has a large stack that can grow in size
dynamically (developers of older, less intelligent operating systemssay,
DOSmight recall a time when even user-space had a fixed-sized stack).<a name="ch02index167"></a><a name="ch02index168"></a></p>
<p>The kernel stack is neither large nor dynamic; it is small and
fixed in size. The exact size of the kernel's stack varies by architecture. On
x86, the stack size is configurable at compile-time and can be either 4 or 8KB.
Historically, the kernel stack is two pages, which generally implies that it is
8KB on 32-bit architectures and 16KB on 64-bit architecturesthis size is fixed
and absolute. Each process receives its own stack.</p>
<p>The kernel stack is discussed in much greater detail in later
chapters.<a name="ch02index169"></a><a name="ch02index170"></a></p>
<a name="ch02lev2sec11"></a>
<h4 class="docSection2Title">Synchronization and Concurrency</h4>
<p>The kernel is susceptible to race conditions. Unlike a
single-threaded user-space application, a number of properties of the kernel
allow for concurrent access of shared resources and thus require synchronization
to prevent races. Specifically,<a name="ch02index171"></a><a name="ch02index172"></a><a name="ch02index173"></a><a name="ch02index174"></a></p>
<ul>
    <li>
    <p>Linux is a preemptive multi-tasking operating system. Processes
    are scheduled and rescheduled at the whim of the kernel's process scheduler. The
    kernel must synchronize between these tasks.</p>
    </li>
    <li>
    <p>The Linux kernel supports multiprocessing. Therefore, without
    proper protection, kernel code executing on two or more processors can access
    the same resource.</p>
    </li>
    <li>
    <p>Interrupts occur asynchronously with respect to the currently
    executing code. Therefore, without proper protection, an interrupt can occur in
    the midst of accessing a shared resource and the interrupt handler can then
    access the same resource.</p>
    </li>
    <li>
    <p>The Linux kernel is preemptive. Therefore, without protection,
    kernel code can be preempted in favor of different code that then accesses the
    same resource.</p>
    </li>
</ul>
<p>Typical solutions to race conditions include spinlocks and
semaphores.<a name="ch02index175"></a><a name="ch02index176"></a><a name="ch02index177"></a><a name="ch02index178"></a></p>
<p>Later chapters provide a thorough discussion of synchronization
and concurrency.</p>
<a name="ch02lev2sec12"></a>
<h4 class="docSection2Title">Portability Is Important</h4>
<p>Although user-space applications do not have to aim for portability, Linux is a portable
operating system and should remain one. This means that architecture-independent
C code must correctly compile and run on a wide range of systems, and that
architecture-dependent code must be properly segregated in system-specific
directories in the kernel source tree.<a name="ch02index179"></a><a name="ch02index180"></a></p>
<p>A handful of rulessuch as remain endian neutral, be 64-bit
clean, do not assume the word or page size, and so ongo a long way. Portability
is discussed in extreme depth in a later chapter.<a name="ch02index181"></a><a name="ch02index182"></a></p>
<br><img src ="http://www.cppblog.com/beautykingdom/aggbug/116129.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/beautykingdom/" target="_blank">chatler</a> 2010-05-22 21:09 <a href="http://www.cppblog.com/beautykingdom/archive/2010/05/22/116129.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>HOWTO compile kernel modules for the kernel 2.6</title><link>http://www.cppblog.com/beautykingdom/archive/2010/04/14/112591.html</link><dc:creator>chatler</dc:creator><author>chatler</author><pubDate>Wed, 14 Apr 2010 15:00:00 GMT</pubDate><guid>http://www.cppblog.com/beautykingdom/archive/2010/04/14/112591.html</guid><wfw:comment>http://www.cppblog.com/beautykingdom/comments/112591.html</wfw:comment><comments>http://www.cppblog.com/beautykingdom/archive/2010/04/14/112591.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/beautykingdom/comments/commentRss/112591.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/beautykingdom/services/trackbacks/112591.html</trackback:ping><description><![CDATA[<pre>
<p><font face="Times New Roman">If you want to compile the sum-module (source mirrored below), follow these steps: </font></p>
<font face="Times New Roman">Create the Makefile in your directory with the sum-module.c</font>
<p><font face="Times New Roman">&nbsp;obj-m&nbsp;&nbsp;&nbsp; := sum-module.o</font></p>
<font face="Times New Roman">KDIR&nbsp;&nbsp;&nbsp; := /lib/modules/$(shell uname -r)/build</font>
<p><font face="Times New Roman">PWD&nbsp;&nbsp;&nbsp; := $(shell pwd)</font></p>
<font face="Times New Roman">default:</font>
<p><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules</font></p>
<font face="Times New Roman">Now do a</font>
<p><font face="Times New Roman">&nbsp;make</font></p>
<font face="Times New Roman">... and the sum-module.ko is built.</font>
<p><font face="Times New Roman">&nbsp;If you get something like this </font></p>
<font face="Times New Roman"># make</font>
<p><font face="Times New Roman">make: Nothing to be done for `default'.</font></p>
<font face="Times New Roman">you need to install the kernel source and compile the kernel first (run "make" at least to the point until<br>&nbsp;all "HOSTCC scripts/" stuff is done - this will configure your kernel and allows external module compilation). <br>Make sure /lib/modules/$(shell uname -r)/build points to your build directory (most likely /usr/src/linux...).</font>
<p><font face="Times New Roman">Another reason for the above error can be, that your browser converted the TAB before $(MAKE) to spaces. <br></font></p>
<p><font face="Times New Roman">Make sure there is a TAB before $(MAKE). </font>
</p>
<p><font face="Times New Roman">Install it with install.sh: </font></p>
<font face="Times New Roman">#!/bin/sh</font>
<p><font face="Times New Roman">install -m 644 sum-module.ko /lib/modules/`uname -r`/kernel/drivers/sum-module.ko</font></p>
<font face="Times New Roman">/sbin/depmod -a</font>
<font face="Times New Roman">(adjust the /lib/modules path according to your needs) </font>
<p><font face="Times New Roman">&nbsp;Now make a </font></p>
<p><font face="Times New Roman"># modprobe sum-module <br></font></p>
<p><font face="Times New Roman">Or if you don't want to install the module, do this: </font></p>
<p><font face="Times New Roman"># insmod ./sum-module.ko</font></p>
<font face="Times New Roman">..and if your system doesn't freeze you've done it right ;-) </font>
<p><font face="Times New Roman">&nbsp;</font></p>
<p><font face="Times New Roman">For kernel 2.4, the Makefile would look like this: </font></p>
<p><font face="Times New Roman">TARGET&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; := modulename</font></p>
<font face="Times New Roman">INCLUDE&nbsp;&nbsp;&nbsp; := -I/lib/modules/`uname -r`/build/include</font>
<p><font face="Times New Roman">CFLAGS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; := -O2 -Wall -DMODULE -D__KERNEL__ -DLINUX</font></p>
<p><font face="Times New Roman">CC&nbsp; := gcc</font>
${TARGET}.o: ${TARGET}.c</p>
<font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $(CC) $(CFLAGS) ${INCLUDE} -c ${TARGET}.c</font>
<p><font face="Times New Roman">&nbsp;(not yet tested) </font></p>
<font face="Times New Roman">sum-module source from: <a  href="http://www.win.tue.nl/%7Eaeb/linux/lk/lk-9.html">http://www.win.tue.nl/~aeb/linux/lk/lk-9.html</a></font>
<p><font face="Times New Roman">/*</font></p>
<p><font face="Times New Roman">&nbsp;* sum-module.c </font></p>
<p><font face="Times New Roman"># modprobe sum-module.o</font></p>
<p><font face="Times New Roman"># ls -l /proc/arith</font></p>
<p><font face="Times New Roman">total 0</font></p>
<p><font face="Times New Roman">dr-xr-xr-x&nbsp;&nbsp;&nbsp; 2 root&nbsp;&nbsp;&nbsp;&nbsp; root&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0 Sep 30 12:40 .</font></p>
<p><font face="Times New Roman">dr-xr-xr-x&nbsp;&nbsp; 89 root&nbsp;&nbsp;&nbsp;&nbsp; root&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0 Sep 30 12:39 ..</font></p>
<p><font face="Times New Roman">-r--r--r--&nbsp;&nbsp;&nbsp; 1 root&nbsp;&nbsp;&nbsp;&nbsp; root&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0 Sep 30 12:40 sum</font></p>
<p><font face="Times New Roman"># cat /proc/arith/sum</font></p>
<p><font face="Times New Roman">0</font></p>
<p><font face="Times New Roman"># echo 7 &gt; /proc/arith/sum</font></p>
<p><font face="Times New Roman"># echo 5 &gt; /proc/arith/sum</font></p>
<p><font face="Times New Roman"># echo 13 &gt; /proc/arith/sum</font></p>
<p><font face="Times New Roman"># cat /proc/arith/sum</font></p>
<p><font face="Times New Roman">25</font></p>
<p><font face="Times New Roman"># rmmod sum-module</font></p>
<p><font face="Times New Roman"># ls -l /proc/arith</font></p>
<p><font face="Times New Roman">ls: /proc/arith: No such file or directory</font></p>
<p><font face="Times New Roman"># </font></p>
<p><font face="Times New Roman">*/</font></p>
<p><font face="Times New Roman">#include &lt;linux/module.h&gt;</font></p>
<font face="Times New Roman">#include &lt;linux/init.h&gt;</font>
<p><font face="Times New Roman">#include &lt;linux/proc_fs.h&gt;</font></p>
<p><font face="Times New Roman">#include &lt;asm/uaccess.h&gt;</font>
</p>
<p><font face="Times New Roman">static unsigned long long sum;</font></p>
<p><font face="Times New Roman">static int show_sum(char *buffer, char **start, off_t offset, int length) {</font></p>
<p><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int size;</font></p>
<font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;    size = sprintf(buffer, "%lld\n", sum);</font>
<p><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *start = buffer + offset;</font></p>
<font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; size -= offset;</font>
<p><font face="Times New Roman">     &nbsp;&nbsp; return (size &gt; length) ? length : (size &gt; 0) ? size : 0;</font></p>
<p><font face="Times New Roman">}</font></p>
<font face="Times New Roman">/* Expect decimal number of at most 9 digits followed by '\n' */</font>
<p><font face="Times New Roman">static int add_to_sum(struct file *file, const char *buffer,</font></p>
<p><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long count, void *data) <br></font></p>
<p><font face="Times New Roman">{</font></p>
<font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long val = 0;</font>
<p><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char buf[10];</font></p>
<span style="font-family: Times New Roman;"> </span><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char *endp;</font>
<br><br>
<p><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (count &gt; sizeof(buf))</font></p>
<font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -EINVAL;</font>
<p><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (copy_from_user(buf, buffer, count))</font></p>
<p><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -EFAULT;</font></p>
<p><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; val = simple_strtoul(buf, &amp;endp, 10);</font></p>
<p><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (*endp != '\n')</font></p>
<p><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -EINVAL;</font></p>
<p><font face="Times New Roman"><br></font></p>
<font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; sum += val;&nbsp;&nbsp;&nbsp;&nbsp; /* mod 2^64 */</font>
<p><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return count;</font></p>
<p><font face="Times New Roman">}</font></p>
<p><font face="Times New Roman">&nbsp;</font></p>
<p><font face="Times New Roman">static int __init sum_init(void) {</font></p>
<p><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct proc_dir_entry *proc_arith;</font></p>
<p><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct proc_dir_entry *proc_arith_sum;</font></p>
<font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; proc_arith = proc_mkdir("arith", 0);</font>
<p><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!proc_arith) {</font></p>
<p><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printk (KERN_ERR "cannot create /proc/arith\n");</font></p>
<p><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -ENOMEM;</font></p>
<p><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</font></p>
<p><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; proc_arith_sum = create_proc_info_entry("arith/sum", 0, 0, show_sum);</font></p>
<p><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!proc_arith_sum) {</font></p>
<p><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printk (KERN_ERR "cannot create /proc/arith/sum\n");</font></p>
<p><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; remove_proc_entry("arith", 0);</font></p>
<p><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -ENOMEM;</font></p>
<p><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</font></p>
<p><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; proc_arith_sum-&gt;write_proc = add_to_sum;</font></p>
<p><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;</font></p>
<p><font face="Times New Roman">}</font></p>
<p><font face="Times New Roman">&nbsp;</font></p>
<p><font face="Times New Roman">static void __exit sum_exit(void) {</font></p>
<p><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; remove_proc_entry("arith/sum", 0);</font></p>
<p><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; remove_proc_entry("arith", 0);</font></p>
<p><font face="Times New Roman">}</font></p>
<p><font face="Times New Roman">module_init(sum_init);</font></p>
<p><font face="Times New Roman">module_exit(sum_exit);</font></p>
<p><font face="Times New Roman">MODULE_LICENSE("GPL");</font></p>
<p><font face="Times New Roman">&nbsp;</font></p>
<p><font face="Times New Roman">&nbsp;from：</font></p>
<p><font face="Times New Roman"><a href="http://www.captain.at/programming/kernel-2.6/">http://www.captain.at/programming/kernel-2.6/ </a></font></p>
</pre>
<a href="http://blog.ednchina.com/fafen/267973/message.aspx">http://blog.ednchina.com/fafen/267973/message.aspx</a>
<br> <img src ="http://www.cppblog.com/beautykingdom/aggbug/112591.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/beautykingdom/" target="_blank">chatler</a> 2010-04-14 23:00 <a href="http://www.cppblog.com/beautykingdom/archive/2010/04/14/112591.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Linux内核中的一些基本编程操作</title><link>http://www.cppblog.com/beautykingdom/archive/2010/04/01/111316.html</link><dc:creator>chatler</dc:creator><author>chatler</author><pubDate>Thu, 01 Apr 2010 11:59:00 GMT</pubDate><guid>http://www.cppblog.com/beautykingdom/archive/2010/04/01/111316.html</guid><wfw:comment>http://www.cppblog.com/beautykingdom/comments/111316.html</wfw:comment><comments>http://www.cppblog.com/beautykingdom/archive/2010/04/01/111316.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/beautykingdom/comments/commentRss/111316.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/beautykingdom/services/trackbacks/111316.html</trackback:ping><description><![CDATA[<div>本文档的Copyleft归yfydz所有，使用GPL发布，可以自由拷贝，转载，转载时请保持文档的完整性，严禁用于任何商业用途。<br>msn: <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#121;&#102;&#121;&#100;&#122;&#95;&#110;&#111;&#49;&#64;&#104;&#111;&#116;&#109;&#97;&#105;&#108;&#46;&#99;&#111;&#109;"><u><font color="#0000ff">yfydz_no1@hotmail.com</font></u></a><br>来源：<a href="http://yfydz.cublog.cn/"><u><font color="#0000ff">http://yfydz.cublog.cn</font></u></a></div>
<div><br>1. 前言</div>
<div>&nbsp;</div>
<div>本文介绍linux内核中一些常用的数据结构和操作。</div>
<div>&nbsp;</div>
<div>2. 双向链表(list)</div>
<div>&nbsp;</div>
<div>linux内核中的双向链表通过结构 struct list_head来将各个节点连接起来，此结构会作为链表元素结构中的一个参数：</div>
<div>struct list_head {<br>&nbsp;struct list_head *next, *prev;<br>};</div>
<div>&nbsp;</div>
<div>链表头的初始化，注意，结构中的指针为NULL并不是初始化，而是指向自身才是初始化，如果只是按普通情况下的置为NULL，而不是指向自身，系统会崩溃，这是一个容易犯的错误：</div>
<div>&nbsp;</div>
<div>#define LIST_HEAD_INIT(name) { &amp;(name), &amp;(name) }</div>
<div>#define LIST_HEAD(name) \<br>&nbsp;struct list_head name = LIST_HEAD_INIT(name)</div>
<div>#define INIT_LIST_HEAD(ptr) do { \<br>&nbsp;(ptr)-&gt;next = (ptr); (ptr)-&gt;prev = (ptr); \<br>} while (0)</div>
<div>&nbsp;</div>
<div>最常用的链表操作：</div>
<div>插入到链表头:<br>void list_add(struct list_head *new, struct list_head *head);</div>
<div>&nbsp;</div>
<div>插入到链表尾:<br>void list_add_tail(struct list_head *new, struct list_head *head);</div>
<div>&nbsp;</div>
<div>删除链表节点:<br>void list_del(struct list_head *entry);</div>
<div>&nbsp;</div>
<div>将节点移动到另一链表:<br>void list_move(struct list_head *list, struct list_head *head);</div>
<div>&nbsp;</div>
<div>将节点移动到链表尾:<br>void list_move_tail(struct list_head *list,struct list_head *head);</div>
<div>&nbsp;</div>
<div>判断链表是否为空，返回1为空，0非空<br>int list_empty(struct list_head *head);</div>
<div>&nbsp;</div>
<div>把两个链表拼接起来：<br>void list_splice(struct list_head *list, struct list_head *head)；</div>
<div>&nbsp;</div>
<div>取得节点指针：<br>#define list_entry(ptr, type, member) \<br>&nbsp;((type *)((char *)(ptr)-(unsigned long)(&amp;((type *)0)-&gt;member)))</div>
<div>&nbsp;</div>
<div>遍历链表中每个节点：<br>#define list_for_each(pos, head) \<br>&nbsp;for (pos = (head)-&gt;next, prefetch(pos-&gt;next); pos != (head); \<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;pos = pos-&gt;next, prefetch(pos-&gt;next))</div>
<div>&nbsp;</div>
<div>逆向循环链表中每个节点：<br>#define list_for_each_prev(pos, head) \<br>&nbsp;for (pos = (head)-&gt;prev, prefetch(pos-&gt;prev); pos != (head); \<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;pos = pos-&gt;prev, prefetch(pos-&gt;prev))</div>
<div>&nbsp;</div>
<div>举例：</div>
<div>&nbsp;</div>
<div>LISH_HEAD(mylist);</div>
<div>&nbsp;</div>
<div>struct my_list{<br>&nbsp;struct list_head list;<br>&nbsp;int data;<br>};</div>
<div>&nbsp;</div>
<div>static int ini_list(void)<br>{<br>&nbsp;struct my_list *p;<br>&nbsp;int i;<br>&nbsp;for(i=0; i&lt;100; i++){<br>&nbsp;&nbsp;p=kmalloc(sizeof(struct my_list), GFP_KERNEL);<br>&nbsp;&nbsp;list_add(&amp;p-&gt;list, &amp;mylist);<br>&nbsp;}<br>}</div>
<div><br>在内存中形成如下结构的一个双向链表：</div>
<div>&nbsp;</div>
<div>&nbsp; +---------------------------------------------------------------+<br>&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |<br>&nbsp; |&nbsp; mylist&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 99&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 98&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |<br>&nbsp; |&nbsp; +----+&nbsp;&nbsp;&nbsp; +---------+&nbsp;&nbsp;&nbsp; +---------+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; +---------+&nbsp;&nbsp; |<br>&nbsp; +-&gt;|next|---&gt;|list.next|---&gt;|list.next|---&gt;...---&gt;|list.next|---+<br>&nbsp;&nbsp;&nbsp;&nbsp; |----|&nbsp;&nbsp;&nbsp; |---------|&nbsp;&nbsp;&nbsp; |---------|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |---------|<br>&nbsp; +--|prev|&lt;---|list.prev|&lt;---|list.prev|&lt;---...&lt;---|list.prev|&lt;--+<br>&nbsp; |&nbsp; +----+&nbsp;&nbsp;&nbsp; |---------|&nbsp;&nbsp;&nbsp; |---------|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |---------|&nbsp;&nbsp; |<br>&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp; data&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp; |&nbsp; data&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp; data&nbsp;&nbsp; |&nbsp;&nbsp; |<br>&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; +---------+&nbsp;&nbsp;&nbsp; +---------+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; +---------+&nbsp;&nbsp; |<br>&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |<br>&nbsp; +---------------------------------------------------------------+</div>
<div>&nbsp;</div>
<div>知道了链表头就能遍历整个链表，如果是用list_add()插入新节点的话，从链表头的next方向看是一个堆栈型。</div>
<div>&nbsp;</div>
<div>从链表中删除节点很容易：</div>
<div>static void del_item(struct my_list *p)<br>{<br>&nbsp;list_del(&amp;p-&gt;list, &amp;mylist);<br>&nbsp;kfree(p);<br>}</div>
<div>&nbsp;</div>
<div>最重要的宏是list_entry，这个宏的思路是根据链表元素结构中链表头结构list_head的地址推算出链表元素结构的实际地址：</div>
<div>&nbsp;</div>
<div>#define list_entry(ptr, type, member) \<br>&nbsp;((type *)((char *)(ptr)-(unsigned long)(&amp;((type *)0)-&gt;member)))</div>
<div>&nbsp;</div>
<div>ptr是链表元素结构(如struct my_list)中链表头结构list_head的地址<br>member是链表元素结构(如struct my_list)中链表头结构list_head参数的名称<br>type是链表元素结构类型(如struct my_list)<br></div>
<div>计算原理是根据链表头结构list_head的地址减去其在链表元素结构中的偏移位置而得到链表元素结构的地址。</div>
<div>&nbsp;</div>
<div>例如：</div>
<div>static void print_list(void)<br>{<br>&nbsp;struct list_head *cur;<br>&nbsp;struct my_list *p;</div>
<div>&nbsp;list_for_each(cur, &amp;mylist){<br>&nbsp;&nbsp;p=list_entry(cur, struct my_list, list);<br>&nbsp;&nbsp;printk("data=%d\n", p-&gt;data);<br>&nbsp;}<br>}</div>
<div>&nbsp;</div>
<div>优点：<br></div>
<div>这样就可以用相同的数据处理方式来描述所有双向链表，不用再单独为各个链表编写各种编辑函数。</div>
<div>&nbsp;</div>
<div>缺点：<br>1) 链表头中元素置为NULL不是初始化，与普通习惯不同；<br>2) 仍然需要单独编写各自的删除整个链表的函数，不能统一处理，因为不能保证所有链表元素结构中链表头结构list_head的偏移地址都是相同的，当然如果把链表头结构list_head都作为链表元素结构的第一个参数，就可以用统一的删除整个链表的函数。</div>
<div><br>3. HASH表</div>
<div>&nbsp;</div>
<div>HASH表适用于不需要对整个空间元素进行排序，而是只需要能快速找到某个元素的场合，是一种以空间换时间的方法，本质也是线性表，但由一个大的线性表拆分为了多个小线性表，由于只需要查找小表，因此搜索速度就会线性查整个大表提高很多，理想情况下，有多少个小线性表，搜索速度就提高了多少倍，通常把小线性表的表头综合为一个数组，大小就是HASH表的数量。</div>
<div>&nbsp;</div>
<div>HASH表速度的关键是HASH函数的设计，HASH函数根据每个元素中固定的参数进行计算，算出一个不大于HASH表数量的索引值，表示该元素需要放在该索引号对应的那个表中，对于固定的参数，计算结果始终是固定的，但对于不同的参数值，希望计算出来的结果能尽可能地平均到每个索引值，HASH函数计算得越平均，表示每个小表中元素的数量都会差不多，这样搜索性能将越好。<span style="color: red;">HASH函数也要尽可能的简单，以减少计算时间，常用的算法是将参数累加求模</span>，在include/linux/jhash.h中已经定义了一些HASH计算函数，可直接使用。</div>
<div>&nbsp;</div>
<div style="color: red;">HASH表在路由cache表，状态连接表等处用得很多。</div>
<div>&nbsp;</div>
<div>举例，连接跟踪中根据tuple值计算HASH：</div>
<div>// net/ipv4/netfilter/ip_conntrack_core.c</div>
<div>u_int32_t<br>hash_conntrack(const struct ip_conntrack_tuple *tuple)<br>{<br>#if 0<br>&nbsp;dump_tuple(tuple);<br>#endif<br>&nbsp;return (jhash_3words(tuple-&gt;src.ip,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (tuple-&gt;dst.ip ^ tuple-&gt;dst.protonum),<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (tuple-&gt;src.u.all | (tuple-&gt;dst.u.all &lt;&lt; 16)),<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ip_conntrack_hash_rnd) % ip_conntrack_htable_size);<br>}</div>
<div>&nbsp;</div>
<div>// include/linux/jhash.h<br>static inline u32 jhash_3words(u32 a, u32 b, u32 c, u32 initval)<br>{<br>&nbsp;a += JHASH_GOLDEN_RATIO;<br>&nbsp;b += JHASH_GOLDEN_RATIO;<br>&nbsp;c += initval;</div>
<div>&nbsp;__jhash_mix(a, b, c);</div>
<div>&nbsp;return c;<br>}</div>
<div>&nbsp;</div>
<div>4. 定时器(timer)</div>
<div>&nbsp;</div>
<div>linux内核定时器由以下结构描述：</div>
<div>&nbsp;</div>
<div>/* include/linux/timer.h */<br>struct timer_list {<br>&nbsp;struct list_head list;<br>&nbsp;unsigned long expires;<br>&nbsp;unsigned long data;<br>&nbsp;void (*function)(unsigned long);<br>};<br></div>
<div>list：timer链表<br>expires：到期时间<br>function：到期函数，时间到期时调用的函数<br>data：传给到期函数的数据，实际应用中通常是一个指针转化而来，该指针指向一个结构</div>
<div><br>timer的操作：</div>
<div>&nbsp;</div>
<div>增加timer，将timer挂接到系统的timer链表：<br>extern void add_timer(struct timer_list * timer);</div>
<div>&nbsp;</div>
<div>删除timer，将timer从系统timer链表中拆除：<br>extern int del_timer(struct timer_list * timer);<br>(del_timer()函数可能会失败，这是因为该timer本来已经不在系统timer链表中了，也就是已经删除过了)</div>
<div>&nbsp;</div>
<div>对于SMP系统，删除timer最好使用下面的函数来防止冲突：<br>extern int del_timer_sync(struct timer_list * timer);</div>
<div>&nbsp;</div>
<div>修改timer，修改timer的到期时间：<br>int mod_timer(struct timer_list *timer, unsigned long expires);</div>
<div>&nbsp;</div>
<div>通常用法：<br><span style="color: red;">&nbsp;&nbsp;&nbsp; struct timer_list通常作为数据结构中的一个参数，在初始化结构的时候初始化timer，表示到期时要进行的操作，实现定时动作，通常更多的是作为超时处理的，timer函数作为超时时的资源释放函数。注意：如果超时了运行超时函数，此时系统是处在时钟中断的bottom half里的，不能进行很复杂的操作，如果要完成一些复杂操作，如到期后的数据发送，不能直接在到期函数中处理，而是应该在到期函数中发个信号给特定内核线程转到top half进行处理。</span></div>
<div>&nbsp;</div>
<div>为判断时间的先后，内核中定义了以下宏来判断：</div>
<div>#define time_after(a,b)&nbsp;&nbsp;((long)(b) - (long)(a) &lt; 0)<br>#define time_before(a,b)&nbsp;time_after(b,a)</div>
<div>#define time_after_eq(a,b)&nbsp;((long)(a) - (long)(b) &gt;= 0)<br>#define time_before_eq(a,b)&nbsp;time_after_eq(b,a)</div>
<div>这里用到了一个技巧，<span style="color: red;">由于linux中的时间是无符号数，这里先将其转换为有符号数后再判断，就能解决时间回绕问题，当然只是一次回绕，回绕两次当然是判断不出来的，具体可自己实验体会。</span></div>
<div>&nbsp;</div>
<div>5. 内核线程(kernel_thread)</div>
<div>&nbsp;</div>
<div>内核中新线程的建立可以用kernel_thread函数实现，该函数在kernel/fork.c中定义：</div>
<div>long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)</div>
<div>fn：内核线程主函数；<br>arg：线程主函数的参数；<br>flags：建立线程的标志；</div>
<div>&nbsp;</div>
<div>内核线程函数通常都调用daemonize()进行后台化作为一个独立的线程运行，然后设置线程的一些参数，如名称，信号处理等，这也不是必须的，然后就进入一个死循环，这是线程的主体部分，这个循环不能一直在运行，否则系统就死在这了，或者是某种事件驱动的，在事件到来前是睡眠的，事件到来后唤醒进行操作，操作完后继续睡眠；或者是定时睡眠，醒后操作完再睡眠；或者加入等待队列通过schedule()调度获得执行时间。总之是不能一直占着 CPU。</div>
<div>&nbsp;</div>
<div>以下是内核线程的一个实例，取自kernel/context.c:</div>
<div>&nbsp;</div>
<div>int start_context_thread(void)<br>{<br>&nbsp;static struct completion startup __initdata = COMPLETION_INITIALIZER(startup);</div>
<div>&nbsp;kernel_thread(context_thread, &amp;startup, CLONE_FS | CLONE_FILES);<br>&nbsp;wait_for_completion(&amp;startup);<br>&nbsp;return 0;<br>}</div>
<div>static int context_thread(void *startup)<br>{<br>&nbsp;struct task_struct *curtask = current;<br>&nbsp;DECLARE_WAITQUEUE(wait, curtask);<br>&nbsp;struct k_sigaction sa;</div>
<div>&nbsp;daemonize();<br>&nbsp;strcpy(curtask-&gt;comm, "keventd");<br>&nbsp;keventd_running = 1;<br>&nbsp;keventd_task = curtask;</div>
<div>&nbsp;spin_lock_irq(&amp;curtask-&gt;sigmask_lock);<br>&nbsp;siginitsetinv(&amp;curtask-&gt;blocked, sigmask(SIGCHLD));<br>&nbsp;recalc_sigpending(curtask);<br>&nbsp;spin_unlock_irq(&amp;curtask-&gt;sigmask_lock);</div>
<div>&nbsp;complete((struct completion *)startup);</div>
<div>&nbsp;/* Install a handler so SIGCLD is delivered */<br>&nbsp;sa.sa.sa_handler = SIG_IGN;<br>&nbsp;sa.sa.sa_flags = 0;<br>&nbsp;siginitset(&amp;sa.sa.sa_mask, sigmask(SIGCHLD));<br>&nbsp;do_sigaction(SIGCHLD, &amp;sa, (struct k_sigaction *)0);</div>
<div>&nbsp;/*<br>&nbsp; * If one of the functions on a task queue re-adds itself<br>&nbsp; * to the task queue we call schedule() in state TASK_RUNNING<br>&nbsp; */<br>&nbsp;for (;;) {<br>&nbsp;&nbsp;set_task_state(curtask, TASK_INTERRUPTIBLE);<br>&nbsp;&nbsp;add_wait_queue(&amp;context_task_wq, &amp;wait);<br>&nbsp;&nbsp;if (TQ_ACTIVE(tq_context))<br>&nbsp;&nbsp;&nbsp;set_task_state(curtask, TASK_RUNNING);<br>&nbsp;&nbsp;schedule();<br>&nbsp;&nbsp;remove_wait_queue(&amp;context_task_wq, &amp;wait);<br>&nbsp;&nbsp;run_task_queue(&amp;tq_context);<br>&nbsp;&nbsp;wake_up(&amp;context_task_done);<br>&nbsp;&nbsp;if (signal_pending(curtask)) {<br>&nbsp;&nbsp;&nbsp;while (waitpid(-1, (unsigned int *)0, __WALL|WNOHANG) &gt; 0)<br>&nbsp;&nbsp;&nbsp;&nbsp;;<br>&nbsp;&nbsp;&nbsp;spin_lock_irq(&amp;curtask-&gt;sigmask_lock);<br>&nbsp;&nbsp;&nbsp;flush_signals(curtask);<br>&nbsp;&nbsp;&nbsp;recalc_sigpending(curtask);<br>&nbsp;&nbsp;&nbsp;spin_unlock_irq(&amp;curtask-&gt;sigmask_lock);<br>&nbsp;&nbsp;}<br>&nbsp;}<br>}</div>
<div>&nbsp;</div>
<div>6. 结构地址</div>
<div>&nbsp;</div>
<div>在C中，结构地址和结构中第一个元素的地址是相同的，因此在linux内核中经常出现使用结构第一个元素的地址来表示结构地址的情况，在读代码时要注意这一点，这和list_entry宏的意思一样。</div>
<div>&nbsp;</div>
<div>如：<br>struct my_struct{<br>&nbsp;int a;<br>&nbsp;int b;<br>}c;</div>
<div>if(&amp;c == &amp;c.a){&nbsp; // always true<br>...<br>}<br><br><br><br>from:<br><br><a href="http://blog.chinaunix.net/u/12313/showart_109612.html">http://blog.chinaunix.net/u/12313/showart_109612.html</a></div><img src ="http://www.cppblog.com/beautykingdom/aggbug/111316.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/beautykingdom/" target="_blank">chatler</a> 2010-04-01 19:59 <a href="http://www.cppblog.com/beautykingdom/archive/2010/04/01/111316.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何在Linux内核中写文件</title><link>http://www.cppblog.com/beautykingdom/archive/2010/02/27/108529.html</link><dc:creator>chatler</dc:creator><author>chatler</author><pubDate>Sat, 27 Feb 2010 03:02:00 GMT</pubDate><guid>http://www.cppblog.com/beautykingdom/archive/2010/02/27/108529.html</guid><wfw:comment>http://www.cppblog.com/beautykingdom/comments/108529.html</wfw:comment><comments>http://www.cppblog.com/beautykingdom/archive/2010/02/27/108529.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/beautykingdom/comments/commentRss/108529.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/beautykingdom/services/trackbacks/108529.html</trackback:ping><description><![CDATA[<p>#include &lt;linux/kernel.h&gt;<br>#include &lt;linux/module.h&gt;<br>#include &lt;linux/init.h&gt;<br>#include &lt;linux/fs.h&gt;<br>#include &lt;linux/string.h&gt;<br>#include &lt;linux/mm.h&gt;<br>#include &lt;linux/syscalls.h&gt;<br>#include &lt;asm/unistd.h&gt;<br>#include &lt;asm/uaccess.h&gt;</p>
<p>#define MY_FILE "/root/LogFile"</p>
<p>char buf[128];<br>struct file *file = NULL;</p>
<p>static int __init init(void)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mm_segment_t old_fs;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printk("Hello, I'm the module that intends to write messages to file.\n");</p>
<p><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(file == NULL)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; file = filp_open(MY_FILE, O_RDWR | O_APPEND | O_CREAT, 0644);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (IS_ERR(file)) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printk("error occured while opening file %s, exiting...\n", MY_FILE);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sprintf(buf,"%s", "The Messages.");</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; old_fs = get_fs();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; set_fs(KERNEL_DS);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; file-&gt;f_op-&gt;write(file, (char *)buf, sizeof(buf), &amp;file-&gt;f_pos);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; set_fs(old_fs);</p>
<p><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>}</p>
<p>static void __exit fini(void)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(file != NULL)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; filp_close(file, NULL);<br>}</p>
<p>module_init(init);<br>module_exit(fini);<br>MODULE_LICENSE("GPL");</p>
<br>from：<br><a href="http://blog.csdn.net/coofive/archive/2006/05/07/712028.aspx">http://blog.csdn.net/coofive/archive/2006/05/07/712028.aspx</a>
<img src ="http://www.cppblog.com/beautykingdom/aggbug/108529.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/beautykingdom/" target="_blank">chatler</a> 2010-02-27 11:02 <a href="http://www.cppblog.com/beautykingdom/archive/2010/02/27/108529.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>What is the difference between user level threads and kernel level threads?</title><link>http://www.cppblog.com/beautykingdom/archive/2010/02/27/108526.html</link><dc:creator>chatler</dc:creator><author>chatler</author><pubDate>Sat, 27 Feb 2010 02:00:00 GMT</pubDate><guid>http://www.cppblog.com/beautykingdom/archive/2010/02/27/108526.html</guid><wfw:comment>http://www.cppblog.com/beautykingdom/comments/108526.html</wfw:comment><comments>http://www.cppblog.com/beautykingdom/archive/2010/02/27/108526.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/beautykingdom/comments/commentRss/108526.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/beautykingdom/services/trackbacks/108526.html</trackback:ping><description><![CDATA[<h1 style="FONT-WEIGHT: normal" class=title_txt>
<p>A kernel thread, sometimes called a LWP (Lightweight Process) is created and scheduled by the kernel. Kernel threads are often more expensive to create than user threads and the system calls to directly create kernel threads are very platform specific. </p>
<p>A user thread is normally created by a threading library and scheduling is managed by the threading library itself (Which runs in user mode). All user threads belong to process that created them. The advantage of user threads is that they are portable. </p>
<p>The major difference can be seen when using multiprocessor systems, user threads completely managed by the threading library can't be ran in parallel on the different CPUs, although this means they will run fine on uniprocessor systems. Since kernel threads use the kernel scheduler, different kernel threads can run on different CPUs. </p>
<p>Many systems implement threading differently, </p>
<p>A many-to-one threading model maps many user processes directly to one kernel thread, the kernel thread can be thought of as the main process. </p>
<p>A one-to-one threading model maps each user thread directly to one kernel thread, this model allows parallel processing on the multiprocessor systems. Each kernel thread can be thought of as a VP (Virtual Process) which is managed by the scheduler. </p>
</h1>
<br>from:<br>http://blog.csdn.net/jicheng687/archive/2009/09/08/4527676.aspx <br><br><br>
<img src ="http://www.cppblog.com/beautykingdom/aggbug/108526.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/beautykingdom/" target="_blank">chatler</a> 2010-02-27 10:00 <a href="http://www.cppblog.com/beautykingdom/archive/2010/02/27/108526.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Linux 内核笔记2 – 进程调度</title><link>http://www.cppblog.com/beautykingdom/archive/2010/02/15/107892.html</link><dc:creator>chatler</dc:creator><author>chatler</author><pubDate>Mon, 15 Feb 2010 07:30:00 GMT</pubDate><guid>http://www.cppblog.com/beautykingdom/archive/2010/02/15/107892.html</guid><wfw:comment>http://www.cppblog.com/beautykingdom/comments/107892.html</wfw:comment><comments>http://www.cppblog.com/beautykingdom/archive/2010/02/15/107892.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/beautykingdom/comments/commentRss/107892.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/beautykingdom/services/trackbacks/107892.html</trackback:ping><description><![CDATA[Linux 内核笔记 &#8211; 进程调度
<br>1	前言
<br>2	调度算法
<br>2.1.1	常用概念
<br>2.1.2	进程数据结构中相关内容
<br>2.1.3	调度算法说明
<br>2.1.4	相关函数
<br>3	调度程序的执行
<br>3.1.1	直接调用
<br>3.1.2	延迟调用
<br>3.1.3	相关函数
<br>4	进程调度示意图
<br>5	SMP系统的调度
<br>6	问题与答案
<br>7	参考文献：
<br>
<br>1	前言
<br>本文的许可协议遵循GNU Free Document
License。协议的具体内容请参见http://www.gnu.org/copyleft/fdl.html。在遵循GNU Free
Document License的基础上，可以自由地传播或发行本文，但请保留本文的完整性。
<br>欢迎大家对这篇文章提出意见和指正，我的email是：shisheng_liu@yahoo.com.cn。
<br>
<br>2	调度算法
<br>2.1.1	常用概念
<br>2.1.1.1	定时中断
<br>    通过硬件的可编程中断控制器8254来实现，定时中断发生的频率由HZ定义，发生的时间间隔被称为tick。
<br>2.1.1.2	CPU节拍（tick）
<br>计算机内部时间的一个计数单位，表示发生一次时钟中断的时间间隔。
<br>2.1.1.3	HZ
<br> 时钟中断发生的频率。在i386机器上，HZ被定义为100，因此时钟中断每10ms一次。
<br>2.1.1.4	CPU时期
<br>      调度是以CPU时期为周期的，在一个CPU时期/调度周期内，系统中所有程序都被执行直到用完当前的时间片，然后所有进程的counter值被重新计算，并开始另一个CPU时期。
<br>2.1.1.5	进程的分类
<br>在调度程序看来，系统中的进程分为两大类，分别是实时进程和普通进程。在任何时候实时进程的执行都高于普通进程。进程数据结构中的policy成
员变量表示了进程是哪一类，而sched_set(/get)scheduler提供了控制进程调度policy的用户级编程接口。
<br>2.1.2	进程数据结构中相关内容
<br>2.1.2.1	   1．nice
<br>    进程的优先级，影响进程获得CPU事件的多少，20为最低，-19为最高。
<br>2.1.2.2	2．counter
<br> 进程时间片所剩余的CPU节拍数。初始值根据进程的nice值决定，在每次时钟中断发生时，也就是一个CPU节拍（tick）的时候，当前进程的counter值减1，如果counter值变为0则表示当前进程的时间片已经用完，系统会重新调度，决定下一个执行的进程。
<br>2.1.2.3	3．need_resched
<br>  标志位。该位在从中断和系统调用中返回的时候被检查，need_resched为1的时候表示要求启动调度程序，这通常发生在进程的时间片已经用完，或者因为IO事件发生而强行抢占当前进程的时候。
<br>2.1.2.4	4．policy
<br>  进程的调度策略。如果调度策略为SCHED_RR或者SCHED_FIFO则表示当前进程为实时进程，否则(SCHED_OTHER)为普通进程。
<br>2.1.3	调度算法说明
<br>Linux采用相当简单但实际证明效果不错的调度算法。在调度的时候，所有正在运行进程的执行权值(goodness)都被计算，最终权值最高的
进程获得执行的机会。假设得到的最大权值为0，就认为本次CPU时期已经执行完毕，会重新计算所有进程的counter值，开始新的CPU时期。调度算法
的核心就是goodness的计算，计算的基本思路如下：
<br>如果等待调度的进程是实时进程，它的goodness为1000 + 本身的优先级,而普通进程的goodness远小于1000，这就保证了实时进程总是优先于普通进程执行。
<br>  如果进程剩余的counter为0,就认为它已经用光了自己在该时期的CPU时间片，goodness返回0。
<br>  对于其他的情况，用下面的公式来计算goodness:
<br>goodness = counter + 20 &#8211; nice；
<br>2.1.4	相关函数
<br>1．schedule()  in kernel/sched.c
<br>主调度函数，选择要运行的进程
<br>2．goodness() in kernel/sched.c
<br>由schedule()调用，计算进程的执行权值
<br>3	调度程序的执行
<br>可以通过两种方式来激活调度程序，分别是直接调用和延迟调用。
<br>3.1.1	直接调用
<br>   当current进程准备主动放弃CPU的时候，它会直接调用调度程序schedule()，将CPU让给另一个进程。
<br>促使current进程主动放弃CPU的原因有两种，一种情况是current需要睡眠（阻塞）来等待所需的资源准备好，此时current的状
态被设置为TASK_INTERRUPTABLE或TASK_UNINTERRUPTABLE，在调用schedule()后进程进入睡眠状态；另一种情
况下进程设置SCHED_YIELD的调度策略，然后调用schedule()，此时进程只是短暂的放弃CPU，在下一次schedule()被调用的时
候进程会继续参与CPU的竞争。
<br>3.1.2	延迟调用
<br>通过设置当前进程的need_resched标志来在其后的某个时刻激活调度程序。前面说过，在从中断/异常/系统调用中返回
时，need_resched标志被检查，在标志不为0的时候会激活调度程序。例如：当时钟中断发生时，中断处理程序检查到当前进程的时间片已经执行完
毕，它就会设置当前进程的need_resched标志；另一个例子是当某个IO中断发生时，中断处理程序发现有进程在等待该IO事件，它会将正在等待的
进程的状态变为执行态，并设置当前进程的need_resched标志。当中断处理程序一结束，系统会重新调度，在这种情况下，新转入执行态的进程很可能
会获得执行机会，从而使系统保持对IO事件的快速响应。
<br>3.1.3	相关函数
<br>  1．wake_up_common() in kernel/sched.c
<br>   激活IO等待队列中的进程，它会顺序调用try_to_wake_up()，reschedule_idle()等函数来要求对进程进程重新调度。
<br>  2．do_timer() in kernel/timer.c
<br>   定时时钟中断程序，减少当前进程的counter值，如果counter已经用完，则设置进程的need_resched域要求重新调度。
<br>  3．ret_from_intr/sys_call/exception   in arch/i386/entry.S
<br>  汇编语言中的程序点，在从中断/异常/系统调用中返回时都会执行这一段程序，检查当前进程的need_resched域，如果不为0就会激活schedule()重新调度。
<br>
<br>
<br>4	进程调度示意图
<br>linux的进程调度如图1所示。<br><img alt=""  src="http://www.cppblog.com/images/cppblog_com/beautykingdom/1.JPG" height="419" width="587">&nbsp; <br><br>6	问题与答案
<br>Q．在当前系统下，调度时间片的长度是多少？
<br>A. 与2.2.x版的内核相比，kernel2.4.x的时间片长度缩短了，对于最高优先级的进程来说，时间片的长度为100ms，默认优先级进程的时间片长度为60ms，而最低优先级进程的时间片长度为10ms。
<br>
<br>Q. Linux如何保证对I/O事件相对比较快的响应速度，这个响应速度是否与调度时间片的长短有关？
<br>A．当I/O事件发生的是时候，对应的中断处理程序被激活，当它发现有进程在等待这个I/O事件的时候，它会激活等待进程，并且设置当前正在执行
进程的need_resched标志，这样在中断处理程序返回的时候，调度程序被激活，原来在等待I/O事件的进程（很可能）获得执行权，从而保证了对I
/O事件的相对快速响应（毫秒级）。
<br>    从上面的说明可以看出，在I/O事件发生的时候，I/O事件的处理进程会抢占当前进程，响应速度与调度时间片的长度无关。
<br>
<br>Q．高优先级(nice)进程和低优先级进程在执行上有何区别？例如一个优先级为-19（最高优先级）的进程和优先级为20（最低）的进程有何区别
<br>A. 进程获得的CPU时间的绝对数目取决于它的初始counter值，初始的counter的计算公式(sched.c in kernel 2.4.14)如下：
<br>p-&gt;counter = (p-&gt;counter &gt;&gt; 1) + ((20 - p-&gt;nice) &gt;&gt; 2) +1)
<br>由公式可以计算出，对于标准进程（p-&gt;nice 为0）， 得到的初始counter为6，即进程获得的时间片为60ms。
<br>最高优先级进程（nice为-19）的初始counter值为10，进程的时间片为100ms。
<br>最低优先级进程（nice为20）的初始counter值为1,进程时间片为10ms。
<br>  结论是最高优先级进程会获得最低优先级进程10倍的执行时间，普通优先级进程接近两倍的执行时间。当然，这是在进程不进行任何IO操作的时候的数据，在有IO操作的时候，进程会经常被迫睡眠来等待IO操作的完成,真正所占用的CPU时间是很难比较的。
<br>我们可以看到每次重新计算counter的时候，新的counter值都要加上它本身剩余值的一半，这种奖励只适用于通过SCHED_YIELD
主动放弃CPU的进程，只有它在重新计算的时候counter值没有用完，所以在计算后counter值会增大，但永远不可能超过20。
<br>
<br>SMP系统中的调度
<br>
<br>7	参考文献：
<br>1．	linux内核源代码版本2.4.14
<br>在任何时候真实的代码总是提供给我们最准确和详细的资料。感谢Linus Torvalds，Alan Cox和其它linux开发者的辛勤劳动。
<br>2．DANIEL P.BOVET &amp; MARCO CESATI
<br>  &lt;&lt;UNDERSTANDING THE LINUX KERNEL&gt;&gt; ISBN: 0-596-00002-2  O&#8217;REILLY 2001
<br>  中译版 《深入理解Linux内核》 陈莉君等译 ISBN: 7-5083-0719-4 中国电力出版社 2001。
<br>本书是专门介绍linux内核结构的书中最详尽的一本，对代码分析讲解的也比较深入，基于2.2的内核版本
<br>3．W.Richard Stevens
<br> 《UNIX环境高级编程》 尤晋元译 ISBN: 7-111-07579-X   机械工业出版社 2000
<br>  UNIX编程圣经，程序员手头必备的书籍之一,对所有UNIX开发人员，无论水平高低，都有参考价值。翻译的水准也难得一见的高明。
<br><br>from:<br>http://www.linuxforum.net/forum/gshowflat.php?Cat=&amp;Board=linuxK&amp;Number=294463&amp;page=16&amp;view=collapsed&amp;sb=5&amp;o=all&amp;fpart=
<br><br> <img src ="http://www.cppblog.com/beautykingdom/aggbug/107892.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/beautykingdom/" target="_blank">chatler</a> 2010-02-15 15:30 <a href="http://www.cppblog.com/beautykingdom/archive/2010/02/15/107892.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>linux块设备，字符设备</title><link>http://www.cppblog.com/beautykingdom/archive/2010/01/28/106630.html</link><dc:creator>chatler</dc:creator><author>chatler</author><pubDate>Thu, 28 Jan 2010 07:00:00 GMT</pubDate><guid>http://www.cppblog.com/beautykingdom/archive/2010/01/28/106630.html</guid><wfw:comment>http://www.cppblog.com/beautykingdom/comments/106630.html</wfw:comment><comments>http://www.cppblog.com/beautykingdom/archive/2010/01/28/106630.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/beautykingdom/comments/commentRss/106630.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/beautykingdom/services/trackbacks/106630.html</trackback:ping><description><![CDATA[
<span style="font-family: 宋体; font-size: 14px; line-height: 26px; "><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; text-indent: 28px; ">字符设备还是块设备的定义属于操作系统的设备访问层，与实际物理设备的特性无必然联系。</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; text-indent: 28px; ">设备访问层下面是驱动程序，所以只要驱动程序提供的方式，都可以。也就是说驱动程序支持stream方式，那么就可以用这种方式访问，驱动程序如果还支持block方式，那么你想用哪种方式访问都可以，典型的比如硬盘式的裸设备，两种都支持块设备（block device）：是一种具有一定结构的随机存取设备，对这种设备的读写是按块进行的，他使用缓冲区来存放暂时的数据，待条件成熟后，从缓存一次性写入设备或从设备中一次性读出放入到缓冲区，如磁盘和文件系统等</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; text-indent: 28px; ">字符设备（Character device）：这是一个顺序的数据流设备，对这种设备的读写是按字符进行的，而且这些字符是连续地形成一个数据流。他不具备缓冲区，所以对这种设备的读写是实时的，如终端、磁带机等。<br>系统中能够随机（不需要按顺序）访问固定大小数据片（chunks）的设备被称作块设备，这些数据片就称作块。最常见的块设备是硬盘，除此以外，还有软盘驱动器、CD-ROM驱动器和闪存等等许多其他块设备。注意，它们都是以安装文件系统的方式使用的——这也是块设备一般的访问方式。</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; text-indent: 28px; ">另一种基本的设备类型是字符设备。字符设备按照字符流的方式被有序访问，像串口和键盘就都属于字符设备。如果一个硬件设备是以字符流的方式被访问的话，那就应该将它归于字符设备；反过来，如果一个设备是随机（无序的）访问的，那么它就属于块设备。</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; text-indent: 28px; ">这两种类型的设备的根本区别在于它们是否可以被随机访问——换句话说就是，能否在访问设备时随意地从一个位置跳转到另一个位置。举个例子，键盘这种设备提供的就是一个数据流，当你敲入&#8220;fox&#8221;这个字符串时，键盘驱动程序会按照和输入完全相同的顺序返回这个由三个字符组成的数据流。如果让键盘驱动程序打乱顺序来读字符串，或读取其他字符，都是没有意义的。所以键盘就是一种典型的字符设备，它提供的就是用户从键盘输入的字符流。对键盘进行读操作会得到一个字符流，首先是&#8220;f&#8221;，然后是&#8220;o&#8221;，最后是&#8220;x&#8221;，最终是文件的结束(EOF)。当没人敲键盘时，字符流就是空的。硬盘设备的情况就不大一样了。硬盘设备的驱动可能要求读取磁盘上任意块的内容，然后又转去读取别的块的内容，而被读取的块在磁盘上位置不一定要连续，所以说硬盘可以被随机访问，而不是以流的方式被访问，显然它是一个块设备。</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; text-indent: 28px; ">内核管理块设备要比管理字符设备细致得多，需要考虑的问题和完成的工作相比字符设备来说要复杂许多。这是因为字符设备仅仅需要控制一个位置—当前位置—而块设备访问的位置必须能够在介质的不同区间前后移动。所以事实上内核不必提供一个专门的子系统来管理字符设备，但是对块设备的管理却必须要有一个专门的提供服务的子系统。不仅仅是因为块设备的复杂性远远高于字符设备，更重要的原因是块设备对执行性能的要求很高；对硬盘每多一分利用都会对整个系统的性能带来提升，其效果要远远比键盘吞吐速度成倍的提高大得多。另外，我们将会看到，块设备的复杂性会为这种优化留下很大的施展空间.</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; text-indent: 28px; ">from:</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; text-indent: 28px; "><a href="http://os.51cto.com/art/200909/151133.htm">http://os.51cto.com/art/200909/151133.htm</a></p></span><img src ="http://www.cppblog.com/beautykingdom/aggbug/106630.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/beautykingdom/" target="_blank">chatler</a> 2010-01-28 15:00 <a href="http://www.cppblog.com/beautykingdom/archive/2010/01/28/106630.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>linux内核模块管理命令</title><link>http://www.cppblog.com/beautykingdom/archive/2009/12/10/102938.html</link><dc:creator>chatler</dc:creator><author>chatler</author><pubDate>Thu, 10 Dec 2009 14:48:00 GMT</pubDate><guid>http://www.cppblog.com/beautykingdom/archive/2009/12/10/102938.html</guid><wfw:comment>http://www.cppblog.com/beautykingdom/comments/102938.html</wfw:comment><comments>http://www.cppblog.com/beautykingdom/archive/2009/12/10/102938.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/beautykingdom/comments/commentRss/102938.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/beautykingdom/services/trackbacks/102938.html</trackback:ping><description><![CDATA[ 1. lsmod 列出已经加载的内核模块
lsmod 是列出目前系统中已加载的模块的名称及大小等；另外我们还可以查看 /proc/modules ，我们一样可以知道系统已经加载的模块。
 
2.modinfo 查看模块信息
modinfo 可以查看模块的信息，通过查看模块信息来判定这个模块的用途。
 
3.modprobe 挂载新模块以及新模块相依赖的模块
  modprobe 我们常用的功能就是挂载模块，在挂载某个内核模块的同时，这个模块所依赖的模块也被同时挂载；当然modprobe 也有列出内核所有模块，还有移除模块的功能；下在我们举个例子说一说咱们常用的功能和参数；
    modprobe [-v] [-V] [-C config-file] [-n] [-i] [-q] [-o ] [parameters...]
    modprobe -r [-n] [-i] [-v] ...
    modprobe -l -t [ -a ...]
 
我们可以看到在/etc/modprobe.conf文件中存在的内容形式如下：
 
alias scsi_hostadapter mptbase
alias scsi_hostadapter1 mptspi


最后一列是模块名字，中间的是模块的别名。那么如果我们知道了一个模块的名字，怎么知道它的别名呢？用下面的命令就可以：
#modprobe -c 
可以查看所有模块的别名

#modprobe -c 模块名 |grep 模块名


 
modprobe -l 是列出内核中所有的模块，包括已挂载和未挂载的；通过modprobe -l ，我们能查看到我们所需要的模块，然后根据我们的需要来挂载；其实modprobe -l 读取的模块列表就位于 /lib/modules/'uname -r' 目录中；其中uname -r 是内核的版本；


  注意： 模块名是不能带有后缀的，我们通过modprobe -l 所看到的模块，都是带有.ko 或.o后缀；

4.rmmod 移除已挂载模块

5.depmod 创建模块依赖关系的列表

这个模块管理工具是创建模块依赖关系的列表，有几个参数我们注意一下就行了，目前的的Linux 发行版所用的内核是2.6x版本，是自动解决依赖关系，所以这个命令知道就行了；模块之前也有依赖关系，比如我们想驱动USB 移动硬盘，目前有两种驱动，一种是udev ，在内核中有，但目前不太稳定；另一种办法是用usb-storage驱动，而usb-storage 依赖的模块是scsi 模块，所以我们要用usb-storage 的模块，也得把scsi 编译安装；

    再举个例子：sata的硬盘，在Linux中的设备表示的是/dev/sd* ，比如 /dev/sda，/dev/sdb 等... 系统要驱动 sata硬盘，则需要把sata在内核中选中，或编译成模块，或内置于内核之中，在此同时，还需要在内核中选中ide ，scsi 的支持等；

    depmod 工具的洋文原意：depmod — program to generate modules.dep and map files.（我译的：为modules.dep 文件或映射文件创建依赖关系）

    [root@localhost beinan]# depmod -a 注：为所有列在/etc/modprobe.conf 或/etc/modules.conf 中的所有模块创建依赖关系，并且写入到modules.dep文件；
    [root@localhost beinan]# depmod -e 注：列出已挂载但不可用的模块；
    [root@localhost beinan]# depmod -n 注：列出所有模块的依赖关系，但仅仅是输出出来 （Write the dependency file on stdout only）

    注：modules.dep 位于 /lib/modules/内核版本 目录

6.insmod 挂载模块

insmod 这个工具，和modprobe 有点类似，但功能上没有modprobe 强，modprobe 在挂载模块是不用指定模块文件的路径，也不用带文件的后缀.o 或.ko ；而insmod 需要的是模块的所在目录的绝对路径，并且一定要带有模块文件名后缀的(modulefile.o 或modulesfile.ko ）

7.与内核模块加载相关的配置文件

模块的配置文件 modules.conf 或 modprobe.conf

    内核模块的开机自动挂载模块一般是位于一个配置文件，一般的Linux发行版本都有 /etc/modules.conf 或 /etc/modprobe.conf 。比如Fedora Core 4.0 内核模块开机自动加载文件是 /etc/modprobe.conf ；在这个文件中，一般是写入模块的加载命令或模块的别名的定义等；比如我们在modules.conf 中可能会发行类似的一行 ；

    alias eth0 8139too

from http://blog.chinaunix.net/u2/76292/showart.php?id=2090623<img src ="http://www.cppblog.com/beautykingdom/aggbug/102938.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/beautykingdom/" target="_blank">chatler</a> 2009-12-10 22:48 <a href="http://www.cppblog.com/beautykingdom/archive/2009/12/10/102938.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Linux "零拷贝" sendfile函数中文说明及实际操作分析</title><link>http://www.cppblog.com/beautykingdom/archive/2009/11/28/102185.html</link><dc:creator>chatler</dc:creator><author>chatler</author><pubDate>Sat, 28 Nov 2009 12:08:00 GMT</pubDate><guid>http://www.cppblog.com/beautykingdom/archive/2009/11/28/102185.html</guid><wfw:comment>http://www.cppblog.com/beautykingdom/comments/102185.html</wfw:comment><comments>http://www.cppblog.com/beautykingdom/archive/2009/11/28/102185.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/beautykingdom/comments/commentRss/102185.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/beautykingdom/services/trackbacks/102185.html</trackback:ping><description><![CDATA[
&nbsp;Sendfile函数说明
<div>&nbsp;</div>
<div>#include &lt;sys/sendfile.h&gt;</div>
<div>ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);</div>
<div>&nbsp;</div>
<div>sendfile()是作用于数据拷贝在两个文件描述符之间的操作函数.这个拷贝操作是内核中操作的,所以称为"零拷贝".sendfile函数比起read和write函数高效得多,因为read和write是要把数据拷贝到用户应用层操作.</div>
<div>&nbsp;</div>
<div>参数说明:</div>
<div>out_fd 是已经打开了,用于写操作(write)的文件描述符;</div>
<div>in_fd 是已经打开了,用于读操作(read)的文件描述符;</div>
<div>offset 偏移量;表示sendfile函数从in_fd中的哪一偏移量开始读取数据.如果是零表示从文件的开始读,否则从相应的便宜量读取.如果是循环读取的时候,下一次offset值应为sendfile函数返回值加上本次的offset的值.</div>
<div>count是在两个描述符之间拷贝的字节数(bytes)</div>
<div>&nbsp;</div>
<div>返回值:</div>
<div>如果成功的拷贝,返回写操作到out_fd的字节数,错误返回-1,并相应的设置error信息.</div>
<div>&nbsp;</div>
<div>EAGAIN 无阻塞I/O设置O_NONBLOCK时,写操作(write)阻塞了.</div>
<div>EBADF 输出或者输入的文件描述符没有打开.</div>
<div>EFAULT 错误的地址.</div>
<div>EINVAL 描述符不可用或者锁定了,或者用mmap()函数操作的in_fd不可用.</div>
<div>EIO 当读取(read)in_fd时发生未知错误.</div>
<div>ENOMEM 读(read)in_fd时内存不足.</div>
<div>&nbsp;</div>
<div>------------------------------------------------------------------------------</div>
<div>&nbsp;</div>
<div>
<div>由于想再提升原有系统中文件传输模块的速度,并减少系统资源占用,进行了一次sendfile()的性能测试,但失败了.不过还是将它用在了模块中.记录一下这次失改的微调测试.</div>
<div>&nbsp;</div>
<div>运行平台: 客户机与服务器均为P4计算机,IDE硬盘; Fedora5发行版; 百兆局域网;</div>
<div>&nbsp;</div>
<div>接收端程序如下:</div>
<div>
<table style="font-size: 12px; width: 88.05%; height: 123px; " align="center">
    <tbody>
        <tr>
            <td>
            <p>&nbsp; FILE *fp = fopen(FILENAME,"wb");</p>
            <p>&nbsp;&nbsp;while((len = recv(sockfd, buff, sizeof(buff), 0)) &gt; 0)<br>&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fwrite(buffer, 1, len, fp);<br>&nbsp;&nbsp;}<br>&nbsp;&nbsp;fclose(fp);</p>
            </td>
        </tr>
    </tbody>
</table>
</div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<div>A. 发送端传统方式代码段如下:</div>
<div>
<table style="font-size: 12px; width: 88.67%; height: 139px; " align="center">
    <tbody>
        <tr>
            <td>&nbsp; fd = open(FILENAME, O_RDONLY);<br>&nbsp;&nbsp;while((len =read(fd, buff, sizeof(buff))) &gt;0)&nbsp;<br>&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; send(sockfd, buff, len ,0);<br>&nbsp;&nbsp;}<br>&nbsp;&nbsp;close(fd);&nbsp;&nbsp;</td>
        </tr>
    </tbody>
</table>
</div>
<p>由于我磁盘分区时指定的块大小为4096,为了最优读取磁盘数据,buff大小设为4096字节.但在测试中发现设为1024或8192不会对传输速度带来影响.</p>
<p>文件大小:9M; 耗时:0.71 - 0.76秒;<br>文件大小:32M; 耗时:2.64 - 2.68秒;<br>文件大小:64M; 耗时:5.36 - 5.43秒;</p>
<p>B. 使用sendfile()传输代码段.<br>
<table style="font-size: 12px; width: 86.6%; height: 143px; " align="center">
    <tbody>
        <tr>
            <td>
            <p>&nbsp; off_t offset = 0;<br>&nbsp;&nbsp;stat(FILENAME, &amp;filestat);</p>
            <p>&nbsp;&nbsp;fd = open(FILENAME, O_RDONLY);<br>&nbsp;&nbsp;sendfile(sockfd, fd, &amp;offset, filestat.st_size) );<br>&nbsp;&nbsp;close(fd);&nbsp;&nbsp;</p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>文件大小:9M; 耗时:0.71 - 1.08秒;<br>文件大小:32M; 耗时:2.66 - 2.74秒;<br>文件大小:64M; 耗时:5.43 - 6.64秒;</p>
<p>似乎还略有下降.根据sendfile的man手册,我在使用该函数前调用了<br>
<table style="font-size: 12px; width: 87.43%; height: 75px; " align="center">
    <tbody>
        <tr>
            <td>
            <p>&nbsp;int no = 1;<br>&nbsp;printf("%d\n", setsockopt(sockfd, IPPROTO_TCP, TCP_CORK, (char*)&amp;no, sizeof(int)) );</p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>文件大小:9M; 耗时:0.72 - 0.75秒;<br>文件大小:32M; 耗时:2.66 - 2.68秒;<br>文件大小:64M; 耗时:5.38 - 5.60秒;</p>
<p>这样似乎达到了传统方式的速度?!不管哪种环境下,我用ethereal抓包显示每一个tcp包的playload部分最大也通常是1448字节.</p>
<p>看来我的测试没有体现出"应用层数据的两次拷贝带来很大的消耗"这一说法.如果按照存在就是有理的说法的话,那我想sendfile()在两种情况下才体现优势,但我却没有环境测试:<br>1. 大并发量的文件服务器或HTTP服务器;<br>2. 内存资源紧张的嵌入式系统;</p>
<p>另外,网络上大量的关于tcp选项中的TCP_CORK描述已经过时.在man手册中早已提到该参数可以与TCP_NODELAY结合使用了.只是,只要设置了TCP_NODELAY选项后,不管是否设置TCP_CORK,包都会立即发出.</p>
<p>----------------------------------------------------------------------</p>
<p>补充:</p>
<p>TCP_NODELAY和TCP_CORK基本上控制了包的&#8220;Nagle化&#8221;，Nagle化在这里的含义是采用Nagle算法把较小的包组装为更大的帧。 John Nagle是Nagle算法的发明人，后者就是用他的名字来命名的，他在1984年首次用这种方法来尝试解决福特汽车公司的网络拥塞问题（欲了解详情请参看IETF RFC 896）。他解决的问题就是所谓的silly window syndrome ，中文称&#8220;愚蠢窗口症候群&#8221;，具体含义是，因为普遍终端应用程序每产生一次击键操作就会发送一个包，而典型情况下一个包会拥有一个字节的数据载荷以及40个字节长的包头，于是产生4000%的过载，很轻易地就能令网络发生拥塞,。 Nagle化后来成了一种标准并且立即在因特网上得以实现。它现在已经成为缺省配置了，但在我们看来，有些场合下把这一选项关掉也是合乎需要的。 </p>
<p>现在让我们假设某个应用程序发出了一个请求，希望发送小块数据。我们可以选择立即发送数据或者等待产生更多的数据然后再一次发送两种策略。如果我们马上发送数据，那么交互性的以及客户/服务器型的应用程序将极大地受益。例如，当我们正在发送一个较短的请求并且等候较大的响应时，相关过载与传输的数据总量相比就会比较低，而且，如果请求立即发出那么响应时间也会快一些。以上操作可以通过设置套接字的TCP_NODELAY选项来完成，这样就禁用了 Nagle算法。 </p>
<p>另外一种情况则需要我们等到数据量达到最大时才通过网络一次发送全部数据，这种数据传输方式有益于大量数据的通信性能，典型的应用就是文件服务器。应用Nagle算法在这种情况下就会产生问题。但是，如果你正在发送大量数据，你可以设置TCP_CORK选项禁用Nagle化，其方式正好同 TCP_NODELAY相反（TCP_CORK 和 TCP_NODELAY 是互相排斥的）。下面就让我们仔细分析下其工作原理。 </p>
<p>假设应用程序使用sendfile()函数来转移大量数据。应用协议通常要求发送某些信息来预先解释数据，这些信息其实就是报头内容。典型情况下报头很小，而且套接字上设置了TCP_NODELAY。有报头的包将被立即传输，在某些情况下（取决于内部的包计数器），因为这个包成功地被对方收到后需要请求对方确认。这样，大量数据的传输就会被推迟而且产生了不必要的网络流量交换。 </p>
<p>但是，如果我们在套接字上设置了TCP_CORK（可以比喻为在管道上插入&#8220;塞子&#8221;）选项，具有报头的包就会填补大量的数据，所有的数据都根据大小自动地通过包传输出去。当数据传输完成时，最好取消TCP_CORK 选项设置给连接&#8220;拔去塞子&#8221;以便任一部分的帧都能发送出去。这同&#8220;塞住&#8221;网络连接同等重要。 </p>
<p>总而言之，如果你肯定能一起发送多个数据集合（例如HTTP响应的头和正文），那么我们建议你设置TCP_CORK选项，这样在这些数据之间不存在延迟。能极大地有益于WWW、FTP以及文件服务器的性能，同时也简化了你的工作。 <br>转自：<br><a href="http://blog.chinaunix.net/u2/76292/showart.php?id=2105375">http://blog.chinaunix.net/u2/76292/showart.php?id=2105375</a><br></p>
</div><img src ="http://www.cppblog.com/beautykingdom/aggbug/102185.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/beautykingdom/" target="_blank">chatler</a> 2009-11-28 20:08 <a href="http://www.cppblog.com/beautykingdom/archive/2009/11/28/102185.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>