<!-- @page { margin: 2cm } P { margin-bottom: 0cm } P.western { font-size: 10pt } P.cjk { font-size: 10pt } H1 { margin-bottom: 0.21cm } H1.western { font-family: "Arial", sans-serif; font-size: 16pt } H1.cjk { font-family: "文鼎PL简中楷"; font-size: 16pt } H1.ctl { font-family: "文鼎PL简中楷"; font-size: 16pt } -->
内核相关: kthread_create 、 kthread_run 、 kthread_stop 、 Asmlinkage 、 HZ tick and jiffie 、 BUG( ) 、 BUG_ON( ) 、 shmat
c相关: <!-- @page { margin: 2cm } P { margin-bottom: 0cm } P.western { font-size: 10pt } P.cjk { font-size: 10pt } H1 { margin-bottom: 0.21cm } H1.western { font-family: "Arial", sans-serif; font-size: 16pt } H1.cjk { font-family: "文鼎PL简中楷"; font-size: 16pt } H1.ctl { font-family: "文鼎PL简中楷"; font-size: 16pt } TD P { margin-bottom: 0cm } A:link { so-language: zxx } --> memchr 、 strncmp 、 sscanf 、 Sprintf 、 isspace
<!-- @page { margin: 2cm } P { margin-bottom: 0cm } P.western { font-size: 10pt } P.cjk { font-size: 10pt } H1 { margin-bottom: 0.21cm } H1.western { font-family: "Arial", sans-serif; font-size: 16pt } H1.cjk { font-family: "文鼎PL简中楷"; font-size: 16pt } H1.ctl { font-family: "文鼎PL简中楷"; font-size: 16pt } -->
使用kthread_create 创建线程: struct task_struct *kthread_create(int (*threadfn)(void *data),
void *data, const char *namefmt, ...); 这个函数可以像printk 一样传入某种格式的线程名 线程创建后,不会马上运行,而是需要将kthread_create() 返回的task_struct 指针传给wake_up_process() ,然后通过此函数运行线程。
当然,还有一个创建并启动线程的函数:kthread_run struct task_struct *kthread_run(int (*threadfn)(void *data), void *data, const char *namefmt, ...);
线程一旦启动起来后,会一直运行,除非该线程主动调用do_exit 函数,或者其他的进程调用kthread_stop 函数,结束线程的运行。 int kthread_stop(struct task_struct *thread); kthread_stop() 通过发送信号给线程。 如果线程函数正在处理一个非常重要的任务,它不会被中断的。当然如果线程函数永远不返回并且不检查信号,它将永远都不会停止。
在执行kthread_stop 的时候,目标线程必须没有退出,否则会Oops 。原因很容易理解,当目标线程退出的时候,其对应的task 结构也变得无 效,kthread_stop 引用该无效task 结构就会出错。
看一下 /usr/include/asm/linkage.h 里面的定义: #define asmlinkage CPP_ASMLINKAGE __attribute__((regparm(0))) __attribute__ 是关键字,是 gcc 的 C 语言 扩展, regparm(0) 表示不从寄存器传递参数
如果是 __attribute__((regparm(3))) ,那么调用函数的时候参数不是通过栈传递,而是直接放到寄存器里,被调用函数直接从 寄存器取参数。
如: asmlinkage long sys_sync(void);
linux 核心每隔固定遧期會發出 timer interrupt (irq 0) , hz 是用來定義每一秒有幾次 timer interrupts 。
tick 是 hz 的倒數,意即 timer interrupt 每發生一次中斷的時間。如 hz 為 250 時, tick 為 4 毫秒 (millisecond) 。
jiffies 為 linux 核心變數 (unsigned long) ,它被用來紀錄系統自開幾以來,已經過多少的 tick 。
作用:一些内核调用可以用来方便标记 bug ,提供断言并输出信息。最常用的 两个是 BUG() 和 BUG_ON() 。当被调用的时候,它们会引发 oops ,导致栈的回溯和错误信息的打印。为什么这些声明会导致 oops 跟硬件的体系结构是相关的。大部分体系结构把 BUG() 和 BUG_ON() 定义成某种非法操作,这样自然会产生需要的 oops 。你可以把这些调用当作断言使用,想要断言某种情况不该发生 : if (bad_thing) BUG(); 或者使用更好的形式: BUG_ON(bad_thing);
可以用 panic() 引发更严重的错误。调用 panic() 不但会打印错误 消息而且还会挂起整个系统。显然,你只应该在极端恶劣的情况下使用它: if (terrible_thing) panic("foo is %ld/n", foo);
有些时候,你只是需要在终端上打印一下栈的回溯信息来帮助你测试。此时可 以使用 dump_stack() 。它只在终端上打印寄存器上下文和函数的跟踪线索: if (!debug_check) { printk(KERN_DEBUG "provide some information.../n"); dump_stack(); } from:http://www.lupaworld.com/bbs/thread-36983-1-8.html
A lots of places in linux kernel we encounter the macro BUG_ON. BUG_ON macro first checks for the condition and if condition is true then it calls BUG which do a printk of msg and call panic which halts the system.( 如果 BUG_ON 中的条件为真就调用 BUG ,它输出一些信息,然后调用 panic 函数挂起系统。 )
The unlikely in BUG_ON macro is compiler directive which ask compiler to generate assembly such that the condition mentioned in unlikely isn't going to be met most-of-the time , which reduces jumps and speeds-up things, although if condition mentioned in unlikely met then there will be a long jump and speed will be effected, so must be used carefully. Same is with likely as it is the opposite of unlikely . (据说 likely 一般是很少用的)
作用 : 共享内存区对象映射到调用进程的地址空间
核心处理函数: void *shmat( int shmid , char *shmaddr , int shmflag );shmat() 是用来允许本进程访问一块共享内存的函数。
int shmid 是那块共享内存的 ID 。
char *shmaddr 是共享内存的起始地址
int shmflag 是本进程对该内存的操作模式。如果是 SHM_RDONLY 的话,就是只读模式。其它的是读写模式
成功时,这个函数返回共享内存的起始地址。失败时返回 -1
最近用到内存共享,收集整理了些资料,做了个简单的对比
原型: extern void *memchr(void *buf, char ch, unsigned count);
头文件: #include <string.h>
功能:从 buf 所指内存区域的前 count 个字节查找字符 ch 。
说明:当第一次遇到字符 ch 时停止查找。如果成功,返回指向字符 ch 的指针;否则返回 NULL 。
原型: extern int strcmp(char *s1,char * s2 , int n);
头文件: #include <string.h>
功能:比较字符串 s1 和 s2 的前 n 个字符。
说明:
当 s1<s2 时,返回值 <0
当 s1=s2 时,返回值 =0
当 s1>s2 时,返回值 >0
函数原型 :
Int sscanf( const char *, const char *, ...);
int scanf( const char *, ...);
头文件: #include<stdio.h>
1. 常见用法。
char buf[512] = ;
sscanf("123456 ", "%s", buf);// 此处 buf 是数组名,它的意思是将 123465 以 %s 的形式存入 buf 中!
返回值:有多少个变量被赋值。 int n= sscanf(str,"%2d%2d",&x,&y);
函数原型 :
#include <stdio.h>
int sprintf(char *string, char *farmat [,argument,...]);
详细描述 : 函数 sprin tf() 的用法和printf() 函数一样,只是 sprintf 的作用是将一个格式化的字符串输出到一个目的字 符串中,而 printf 是将一个格式化的字符串输出到屏幕。
例如: sprintf(s, "%d", 123); // 把整数 123 打印成一个字符串保存在 s 中。
返回值: 返回本次函数调用打印到字符缓冲区中的字符数目
#include<ctype.h >
定义函数
int isspace(int c)
函数说明 : 检查参数 c 是否为空格字符,也就是判断是否为空格 ('') 、定位字符 ('/t') 、 CR('/r') 、换行 ('/n') 、垂直定位字符 ('/v') 或翻页 (' /f') 的情况。
返回值 : 若参数 c 为空格字符,则返回 TRUE ,否则返回 NULL(0) 。
附加说明 : 此为宏定义,非真正函数。
基本 C 库函数
当编写驱动程序时,一般情况下不能使用C 标准库的函数。Linux 内核也提供了与标准库函数功能相同的一些函数,但二者还是稍有差别。
类别
函数名
功能
函数形成
参数
描述
字符串转换
simple_strtol
把一个字符串转换为一个有符号长整数
long simple_strtol (const char * cp, char ** endp, unsigned int base)
cp 指向字符串的开始,endp 为指向要分析的字符串末尾处的位置,base 为要用的基数。
simple_strtoll
把一个字符串转换为一个有符号长长整数
long long simple_strtoll (const char * cp, char ** endp, unsigned int base)
cp 指向字符串的开始,endp 为指向要分析的字符串末尾处的位置,base 为要用的基数。
simple_strtoul
把一个字符串转换为一个无符号长整数
long long simple_strtoul (const char * cp, char ** endp, unsigned int base)
cp 指向字符串的开始,endp 为指向要分析的字符串末尾处的位置,base 为要用的基数。
simple_strtoull
把一个字符串转换为一个无符号长长整数
long long simple_strtoull (const char * cp, char ** endp, unsigned int base)
cp 指向字符串的开始,endp 为指向要分析的字符串末尾处的位置,base 为要用的基数。
vsnprintf
格式化一个字符串,并把它放在缓存中。
int vsnprintf (char * buf, size_t size, const char * fmt, va_list args)
buf 为存放结果的缓冲区, size 为缓冲区的大小,fmt 为要使用的格式化字符串,args 为格式化字符串的参数。
snprintf
格式化一个字符串,并把它放在缓存中。
int snprintf (char * buf, size_t size, const char * fmt, ... ...)
buf 为存放结果的缓冲区, size 为缓冲区的大小,fmt 为格式化字符串,使用@… 来对格式化字符串进行格式化,…为可变参数。
vsprintf
格式化一个字符串,并把它放在缓存中。
int vsprintf (char * buf, const char * fmt, va_list args)
buf 为存放结果的缓冲区, size 为缓冲区的大小,fmt 为要使用的格式化字符串,args 为格式化字符串的参数。
sprintf
格式化一个字符串,并把它放在缓存中。
int sprintf (char * buf, const char * fmt, ... ...)
buf 为存放结果的缓冲区, size 为缓冲区的大小,fmt 为格式化字符串,使用@… 来对格式化字符串进行格式化,…为可变参数。
字符串操作
strcpy
拷贝一个以NUL 结束的字符串
char * strcpy (char * dest, const char * src)
dest 为目的字符串的位置, src 为源字符串的位置。
strncpy
拷贝一个定长的、以NUL 结束的字符串
char * strncpy (char * dest, const char * src, size_t count)
dest 为目的字符串的位置, src 为源字符串的位置,count 为要拷贝的最大字节数
与用户空间的strncpy 不同,这个函数并不用NUL 填充缓冲区,如果与源串超过count ,则结果以非NUL 结束
strcat
把一个以NUL 结束的字符串添加到另一个串的末尾
char * strcat (char * dest, const char * src)
dest 为要添加的字符串, src 为源字符串。
strncat
把一个定长的、以NUL 结束的字符串添加到另一个串的末尾
char * strncat (char * dest, const char * src, size_t count)
dest 为要添加的字符串, src 为源字符串,count 为要拷贝的最大字节数
注意,与strncpy, 形成对照, strncat 正常结束。
strchr
在一个字符串中查找第一次出现的某个字 符
char * strchr (const char * s, int c)
s 为被搜索的字符串,c 为待搜索的字符。
strrchr
在一个字符串中查找最后一次出现的某个 字符
char * strrchr (const char * s, int c)
s 为被搜索的字符串,c 为待搜索的字符。
strlen
给出一个字符串的长度
size_t strlen (const char * s)
s 为给定的字符串
strnlen
给出给定长度字符串的长度
size_t strnlen (const char * s, size_t count)
s 为给定的字符串
strpbrk
在一个字符串中查找第一次出现的一组字 符
char * strpbrk (const char * cs, const char * ct)
cs 为被搜索的字符串,ct 为待搜索的一组字符
strtok
把一个字符串分割为子串
char * strtok (char * s, const char * ct)
s 为被搜索的字符串,ct 为待搜索的子串
注意,一般不提倡用这个函数,而应当用strsep
memset
用给定的值填充内存区
void * memset (void * s, int c, size_t count)
s 为指向内存区起始的指针,c 为 要填充的内 容,count 为 内存区的大小
I/O 空间的访问不能使用memset ,而应当使用memset_io 。
bcopy
把内存的一个区域拷贝到另一个区域
char * bcopy (const char * src, char * dest, int count)
src 为源字符串,dest 为目的字符串,而count 为内存区的大小
注意,这个函数的功能与memcpy 相同,这是从BSD 遗留下来的,对I/O 空间的访问应当用memcpy_toio 或 memcpy_fromio
memcpy
把内存的一个区域拷贝到另一个区域
void * memcpy (void * dest, const void * src, size_t count)
dest 为目的字符串,Src 为源字符串,而count 为内存区的大小
对I/O 空间的访问应当用memcpy_toio 或 memcpy_fromio
memmove
把内存的一个区域拷贝到另一个区域
void * memmove (void * dest, const void * src, size_t count)
dest 为目的字符串,Src 为源字符串,而count 为内存区的大小
memcpy 和memmove 处理重叠的区域,而该函数不处理。
memcmp
比较内存的两个区域
int memcmp (const void * cs, const void * ct, size_t count)
cs 为一个内存区,ct 为另一个内存区,而count 为内存区的大小
memscan
在一个内存区中查找一个字符
void * memscan (void * addr, int c, size_t size)
addr 为内存区,c 为要搜索的字符,而size 为内存区的大小
返回c 第一次出现的地址,如果没有找到c ,则向该内存区传递一个字节。
strstr
在以NUL 结束的串中查找第一个出现的子串
char * strstr (const char * s1, const char * s2)
s1 为被搜索的串,s2 为待搜索的串。
memchr
在一个内存区中查找一个字符
void * memchr (const void * s, int c, size_t n)
s 为内存区,为待搜索的字符,n 为内存的大小
返回c 第一次出现的位置,如果没有找到c ,则返回空。
位操作
set_bit
在位图中原子地设置某一位
void set_bit (int nr, volatile void * addr)
nr 为要设置的位,addr 为位图的起始地址
这个函数是原子操作,如果不需要原子操 作,则调用__set_bit 函数,nr 可以任意大,位图的大小不限于一个字。
__set_bit
在位图中设置某一位
void __set_bit (int nr, volatile void * addr)
nr 为要设置的位,addr 为位图的起始地址
clear_bit
在位图中清某一位
void clear_bit (int nr, volatile void * addr)
nr 为要清的位,addr 为位图的起始地址
该函数是原子操作,但不具有加锁功能, 如果要用于加锁目的,应当调用smp_mb__before_clear_bit 或smp_mb__after_clear_bit 函数,以确保任何改变在其他的处理器上是可见的。
__change_bit
在位图中改变某一位
void __change_bit (int nr, volatile void * addr)
nr 为要设置的位,addr 为位图的起始地址。
与change_bit 不同,该函数是非原子操 作。
change_bit
在位图中改变某一位
void change_bit (int nr, volatile void * addr)
nr 为要设置的位,addr 为位图的起始地址。
test_and_set_bit
设置某一位并返回该位原来的值
int test_and_set_bit (int nr, volatile void * addr)
nr 为要设置的位,addr 为位图的起始地址。
该函数是原子操作
__test_and_set_bit
设置某一位并返回该位原来的值
int __test_and_set_bit (int nr, volatile void * addr)
nr 为要设置的位,addr 为位图的起始地址。
该函数是非原子操作,如果这个操作的两 个实例发生竞争,则一个成功而另一个失败,因此应当用一个锁来保护对某一位的多个访问。
test_and_clear_bit
清某一位,并返回原来的值
int test_and_clear_bit (int nr, volatile void * addr);
nr 为要设置的位,addr 为位图的起始地址。
该函数是原子操作
__test_and_clear_bit
清某一位,并返回原来的值
int __test_and_clear_bit (int nr, volatile void * addr);
nr 为要设置的位,addr 为位图的起始地址。
该函数为非原子操作
test_and_change_bit
改变某一位并返回该位的新值
int test_and_change_bit (int nr, volatile void * addr)
nr 为要设置的位,addr 为位图的起始地址。
该函数为原子操作
test_bit
确定某位是否被设置
int test_bit (int nr, const volatile void * addr)
nr 为要测试的第几位,addr 为位图的起始地址。
find_first_zero_bit
在内存区中查找第一个值为0 的位
int find_first_zero_bit (void * addr, unsigned size)
addr 为内存区的起始地址,size 为要查找的最大长度
返回第一个位为0 的位号
find_next_zero_bit
在内存区中查找第一个值为0 的位
int find_next_zero_bit (void * addr, int size, int offset)
addr 为内存区的起始地址,size 为要查找的最大长度,offset 开始搜索的起始位号。
ffz
在字中查找第一个0
unsigned long ffz (unsigned long word);
word 为要搜索的字。
ffs
查找第一个已设置的位
int ffs (int x)
x 为要搜索的字。
这个函数的定义方式与Libc 中的一样。
hweight32
返回一个N 位 字的加权平衡值
hweight32 ( x)
x 为要加权的字
一个数的加权平衡是这个数所有位的总和。
使用kthread_create 创建线程: struct task_struct *kthread_create(int (*threadfn)(void *data),
void *data, const char *namefmt, ...); 这个函数可以像printk 一样传入某种格式的线程名 线程创建后,不会马上运行,而是需要将kthread_create() 返回的task_struct 指针传给wake_up_process() ,然后通过此函数运行线程。
当然,还有一个创建并启动线程的函数:kthread_run struct task_struct *kthread_run(int (*threadfn)(void *data), void *data, const char *namefmt, ...);
线程一旦启动起来后,会一直运行,除非该线程主动调用do_exit 函数,或者其他的进程调用kthread_stop 函数,结束线程的运行。 int kthread_stop(struct task_struct *thread); kthread_stop() 通过发送信号给线程。 如果线程函数正在处理一个非常重要的任务,它不会被中断的。当然如果线程函数永远不返回并且不检查信号,它将永远都不会停止。
在执行kthread_stop 的时候,目标线程必须没有退出,否则会Oops 。原因很容易理解,当目标线程退出的时候,其对应的task 结构也变得无 效,kthread_stop 引用该无效task 结构就会出错。
看一下 /usr/include/asm/linkage.h 里面的定义: #define asmlinkage CPP_ASMLINKAGE __attribute__((regparm(0))) __attribute__ 是关键字,是 gcc 的 C 语言 扩展, regparm(0) 表示不从寄存器传递参数
如果是 __attribute__((regparm(3))) ,那么调用函数的时候参数不是通过栈传递,而是直接放到寄存器里,被调用函数直接从 寄存器取参数。
如: asmlinkage long sys_sync(void);
linux 核心每隔固定遧期會發出 timer interrupt (irq 0) , hz 是用來定義每一秒有幾次 timer interrupts 。
tick 是 hz 的倒數,意即 timer interrupt 每發生一次中斷的時間。如 hz 為 250 時, tick 為 4 毫秒 (millisecond) 。
jiffies 為 linux 核心變數 (unsigned long) ,它被用來紀錄系統自開幾以來,已經過多少的 tick 。
作用:一些内核调用可以用来方便标记 bug ,提供断言并输出信息。最常用的 两个是 BUG() 和 BUG_ON() 。当被调用的时候,它们会引发 oops ,导致栈的回溯和错误信息的打印。为什么这些声明会导致 oops 跟硬件的体系结构是相关的。大部分体系结构把 BUG() 和 BUG_ON() 定义成某种非法操作,这样自然会产生需要的 oops 。你可以把这些调用当作断言使用,想要断言某种情况不该发生 : if (bad_thing) BUG(); 或者使用更好的形式: BUG_ON(bad_thing);
可以用 panic() 引发更严重的错误。调用 panic() 不但会打印错误 消息而且还会挂起整个系统。显然,你只应该在极端恶劣的情况下使用它: if (terrible_thing) panic("foo is %ld/n", foo);
有些时候,你只是需要在终端上打印一下栈的回溯信息来帮助你测试。此时可 以使用 dump_stack() 。它只在终端上打印寄存器上下文和函数的跟踪线索: if (!debug_check) { printk(KERN_DEBUG "provide some information.../n"); dump_stack(); } from:http://www.lupaworld.com/bbs/thread-36983-1-8.html
A lots of places in linux kernel we encounter the macro BUG_ON. BUG_ON macro first checks for the condition and if condition is true then it calls BUG which do a printk of msg and call panic which halts the system.( 如果 BUG_ON 中的条件为真就调用 BUG ,它输出一些信息,然后调用 panic 函数挂起系统。 )
The unlikely in BUG_ON macro is compiler directive which ask compiler to generate assembly such that the condition mentioned in unlikely isn't going to be met most-of-the time , which reduces jumps and speeds-up things, although if condition mentioned in unlikely met then there will be a long jump and speed will be effected, so must be used carefully. Same is with likely as it is the opposite of unlikely . (据说 likely 一般是很少用的)
作用 : 共享内存区对象映射到调用进程的地址空间
核心处理函数: void *shmat( int shmid , char *shmaddr , int shmflag );shmat() 是用来允许本进程访问一块共享内存的函数。
int shmid 是那块共享内存的 ID 。
char *shmaddr 是共享内存的起始地址
int shmflag 是本进程对该内存的操作模式。如果是 SHM_RDONLY 的话,就是只读模式。其它的是读写模式
成功时,这个函数返回共享内存的起始地址。失败时返回 -1
最近用到内存共享,收集整理了些资料,做了个简单的对比
