void *kmalloc(size_t size, gfp_t flags);
kmalloc() 申请的内存位于物理内存映射区域,而且在物理上也是连续的,它们与真实的物理地址只有一个固定的偏移,因为存在较简单的转换关系,所以对申请的内存大小有限制,不能超过128KB
/*较常用的 flags(分配内存的方法):
GFP_ATOMIC —— 分配内存的过程是一个原子过程,分配内存的过程不会被(高优先级进程或中断)打断;
GFP_KERNEL —— 正常分配内存;
GFP_DMA —— 给 DMA 控制器分配内存,需要使用该标志(DMA要求分配虚拟地址和物理地址连续)。
flags 的参考用法:
|– 进程上下文,可以睡眠 GFP_KERNEL
|– 进程上下文,不可以睡眠 GFP_ATOMIC
| |– 中断处理程序 GFP_ATOMIC
| |– 软中断 GFP_ATOMIC
| |– Tasklet GFP_ATOMIC
|– 用于DMA的内存,可以睡眠 GFP_DMA | GFP_KERNEL
|– 用于DMA的内存,不可以睡眠 GFP_DMA |GFP_ATOMIC
*/
void kfree(const void *objp);
/**
* kzalloc - allocate memory. The memory is set to zero.
* @size: how many bytes of memory are required.
* @flags: the type of memory to allocate (see kmalloc).
*/
static inline void *kzalloc(size_t size, gfp_t flags)
{
return kmalloc(size, flags | __GFP_ZERO);
}
kzalloc() 函数与 kmalloc() 非常相似,参数及返回值是一样的,可以说是前者是后者的一个变种,因为 kzalloc() 实际上只是额外附加了 __GFP_ZERO 标志。所以它除了申请内核内存外,还会对申请到的内存内容清零
void kfree(const void *objp);
void *vmalloc(unsigned long size);
vmalloc() 函数则会在虚拟内存空间给出一块连续的内存区,但这片连续的虚拟内存在物理内存中并不一定连续。由于 vmalloc() 没有保证申请到的是连续的物理内存,因此对申请的内存大小没有限制,如果需要申请较大的内存空间就需要用此函数了,该函数可以睡眠,不能在中断上下文中调用
void vfree(const void *addr);
设备的中断会打断内核中进程的正常调度和运行,系统对更高吞吐率的追求势必要求中断服务程序尽可能地短小精悍。中断要尽可能耗时比较短,尽快恢复系统正常调试,所以把中断触发、中断执行分开,也就是所说的“上半部分(中断触发)、底半部(中断执行)”,其实就是我们后面说的中断上下文。
tasklet:
Void my_tasklet_func(unsigned long)
//静态创建
static DECLARE_TASKLET(my_tasklet,my_tasklet_func,data)
//动态创建
DECLARE_TASKLET(my_tasklet,my_tasklet_func,data)
Tasklet_schedule(&my_tasklet)
定时器:
//声明方式一
struct timer_list mytimer;
setup_timer(&mytimer, (*function)(unsigned long), unsigned long data);
mytimer.expires = jiffies + 5*HZ;
DEFINE_TIMER(timer_name, function_name, expires_value, data);
//声明方式二
struct timer_list mytimer;
setup_timer(&mytimer, (*function)(unsigned long), unsigned long data);
mytimer.expires = jiffies + 5*HZ;
//声明方式三
struct timer_list mytimer;
init_timer(&mytimer);
mytimer ->timer.expires = jiffies + 5*HZ;
mytimer ->timer.data = (unsigned long) dev;
mytimer ->timer.function = &corkscrew_timer; /* timer handler */
//使能定时器
add_timer(struct timer_list *timer)
//mod_timer一般放在定时器handler内,循环
mod_timer(struct timer_list *timer, unsigned long expires)
//删除定时器
del_timer(struct timer_list *timer) && del_timer_sync(struct timer_list *timer)
工作队列:
http://www.cnblogs.com/wwang/archive/2010/10/27/1862202.html
/*1> 使用缺省的工作队列*/
//初始化指定工作,目的是把用户指定的函数_func及_func需要的参数_data赋给work_struct的func及data变量。
INIT_WORK(_work, _func, _data);
//对工作进行调度,即把给定工作的处理函数提交给缺省的工作队列和工作者线程。工作者线程本质上是一个普通的内核线程,在默认情况下,每个CPU均有一个类型为“events”的工作者线程,当调用schedule_work时,这个工作者线程会被唤醒去执行工作链表上的所有工作。
int schedule_work(struct work_struct *work);
//延迟执行工作,与schedule_work类似。
int schedule_delayed_work(struct work_struct *work, unsigned long delay);
//刷新缺省工作队列。此函数会一直等待,直到队列中的所有工作都被执行。
void flush_scheduled_work(void);
//flush_scheduled_work并不取消任何延迟执行的工作,因此,如果要取消延迟工作,应该调用cancel_delayed_work。
int cancel_delayed_work(struct work_struct *work);
/*2> 自己创建一个工作队列*/
//创建新的工作队列和相应的工作者线程,name用于该内核线程的命名
struct workqueue_struct *create_workqueue(const char *name);
//类似于schedule_work,区别在于queue_work把给定工作提交给创建的工作队列wq而不是缺省队列。
int queue_work(struct workqueue_struct *wq, struct work_struct *work);
//延迟执行工作。
int queue_delayed_work(struct workqueue_struct *wq, struct work_struct *work, unsigned long delay);
//刷新指定工作队列。
void flush_workqueue(struct workqueue_struct *wq);
//释放创建的工作队列。
void destroy_workqueue(struct workqueue_struct *wq);
INIT_WORK(struct work_struct *work, work_func_t func);
INIT_DELAYED_WORK(struct delayed_work *work, work_func_t func);
int schedule_work(struct work_struct *work);
int schedule_delayed_work(struct delayed_work *work, unsigned long delay);
struct workqueue_struct *create_workqueue(const char *name);
int queue_work(struct workqueue_struct *wq, struct work_struct *work);
int queue_delayed_work(struct workqueue_struct *wq, struct delayed_work *work, unsigned long delay);
void flush_scheduled_work(void);
void flush_workqueue(struct workqueue_struct *wq);
int cancel_delayed_work(struct delayed_work *work);
void destroy_workqueue(struct workqueue_struct *wq);
void *mmap(void *addr,size_t length ,int prot, int flags, int fd, off_t offset)
文件映射是虚存的中心概念, 文件映射一方面给用户提供了一组措施, 好似用户将文件映射到自己地址空间的某个部分, 使用简单的内存访问指令读写文件;另一方面, 它也可以用于内核的基本组织模式, 在这种模式种, 内核将整个地址空间视为诸如文件之类的一组不同对象的映射. 中的传统文件访问方式是, 首先用open系统调用打开文件, 然后使用read, write以及lseek等调用进行顺序或者随即的I/O. 这种方式是非常低效的, 每一次I/O操作都需要一次系统调用. 另外, 如果若干个进程访问同一个文件, 每个进程都要在自己的地址空间维护一个副本, 浪费了内存空间. 而如果能够通过一定的机制将页面映射到进程的地址空间中, 也就是说首先通过简单的产生某些内存管理数据结构完成映射的创建. 当进程访问页面时产生一个缺页中断, 内核将页面读入内存并且更新页表指向该页面. 而且这种方式非常方便于同一副本的共享
spinlock自旋锁是如何实现的