linuxmsleep
Ⅰ 一文搞懂 , linux内核—— 同步管理(下)
上面讲的自旋锁,信号量和互斥锁的实现,都是使用了原子操作指令。由于原子操作会 lock,当线程在多个 CPU 上争抢进入临界区的时候,都会操作那个在多个 CPU 之间共享的数据 lock。CPU 0 操作了 lock,为了数据的一致性,CPU 0 的操作会导致其他 CPU 的 L1 中的 lock 变成 invalid,在随后的来自其他 CPU 对 lock 的访问会导致 L1 cache miss(更准确的说是communication cache miss),必须从下一个 level 的 cache 中获取。
这就会使缓存一致性变得很糟,导致性能下降。所以内核提供一种新的同步方式:RCU(读-复制-更新)。
RCU 解决了什么
RCU 是读写锁的高性能版本,它的核心理念是读者访问的同时,写者可以更新访问对象的副本,但写者需要等待所有读者完成访问之后,才能删除老对象。读者没有任何同步开销,而写者的同步开销则取决于使用的写者间同步机制。
RCU 适用于需要频繁的读取数据,而相应修改数据并不多的情景,例如在文件系统中,经常需要查找定位目录,而对目录的修改相对来说并不多,这就是 RCU 发挥作用的最佳场景。
RCU 例子
RCU 常用的接口如下图所示:
为了更好的理解,在剖析 RCU 之前先看一个例子:
#include<linux/kernel.h>#include<linux/mole.h>#include<linux/init.h>#include<linux/slab.h>#include<linux/spinlock.h>#include<linux/rcupdate.h>#include<linux/kthread.h>#include<linux/delay.h>structfoo{inta;structrcu_headrcu;};staticstructfoo*g_ptr;staticintmyrcu_reader_thread1(void*data)//读者线程1{structfoo*p1=NULL;while(1){if(kthread_should_stop())break;msleep(20);rcu_read_lock();mdelay(200);p1=rcu_dereference(g_ptr);if(p1)printk("%s: read a=%d\n",__func__,p1->a);rcu_read_unlock();}return0;}staticintmyrcu_reader_thread2(void*data)//读者线程2{structfoo*p2=NULL;while(1){if(kthread_should_stop())break;msleep(30);rcu_read_lock();mdelay(100);p2=rcu_dereference(g_ptr);if(p2)printk("%s: read a=%d\n",__func__,p2->a);rcu_read_unlock();}return0;}staticvoidmyrcu_del(structrcu_head*rh)//回收处理操作{structfoo*p=container_of(rh,structfoo,rcu);printk("%s: a=%d\n",__func__,p->a);kfree(p);}staticintmyrcu_writer_thread(void*p)//写者线程{structfoo*old;structfoo*new_ptr;intvalue=(unsignedlong)p;while(1){if(kthread_should_stop())break;msleep(250);new_ptr=kmalloc(sizeof(structfoo),GFP_KERNEL);old=g_ptr;*new_ptr=*old;new_ptr->a=value;rcu_assign_pointer(g_ptr,new_ptr);call_rcu(&old->rcu,myrcu_del);printk("%s: write to new %d\n",__func__,value);value++;}return0;}staticstructtask_struct*reader_thread1;staticstructtask_struct*reader_thread2;staticstructtask_struct*writer_thread;staticint__initmy_test_init(void){intvalue=5;printk("figo: my mole init\n");g_ptr=kzalloc(sizeof(structfoo),GFP_KERNEL);reader_thread1=kthread_run(myrcu_reader_thread1,NULL,"rcu_reader1");reader_thread2=kthread_run(myrcu_reader_thread2,NULL,"rcu_reader2");writer_thread=kthread_run(myrcu_writer_thread,(void*)(unsignedlong)value,"rcu_writer");return0;}staticvoid__exitmy_test_exit(void){printk("goodbye\n");kthread_stop(reader_thread1);kthread_stop(reader_thread2);kthread_stop(writer_thread);if(g_ptr)kfree(g_ptr);}MODULE_LICENSE("GPL");mole_init(my_test_init);mole_exit(my_test_exit);
执行结果是:
myrcu_reader_thread2:reada=0myrcu_reader_thread1:reada=0myrcu_reader_thread2:reada=0myrcu_writer_thread:writetonew5myrcu_reader_thread2:reada=5myrcu_reader_thread1:reada=5myrcu_del:a=0
RCU 原理
可以用下面一张图来总结,当写线程 myrcu_writer_thread 写完后,会更新到另外两个读线程 myrcu_reader_thread1 和 myrcu_reader_thread2。读线程像是订阅者,一旦写线程对临界区有更新,写线程就像发布者一样通知到订阅者那里,如下图所示。
写者在拷贝副本修改后进行 update 时,首先把旧的临界资源数据移除(Removal);然后把旧的数据进行回收(Reclamation)。结合 API 实现就是,首先使用 rcu_assign_pointer 来移除旧的指针指向,指向更新后的临界资源;然后使用 synchronize_rcu 或 call_rcu 来启动 Reclaimer,对旧的临界资源进行回收(其中 synchronize_rcu 表示同步等待回收,call_rcu 表示异步回收)。
为了确保没有读者正在访问要回收的临界资源,Reclaimer 需要等待所有的读者退出临界区,这个等待的时间叫做宽限期(Grace Period)。
Grace Period
中间的黄色部分代表的就是 Grace Period,中文叫做宽限期,从 Removal 到 Reclamation,中间就隔了一个宽限期,只有当宽限期结束后,才会触发回收的工作。宽限期的结束代表着 Reader 都已经退出了临界区,因此回收工作也就是安全的操作了。
宽限期是否结束,与 CPU 的执行状态检测有关,也就是检测静止状态 Quiescent Status。
Quiescent Status
Quiescent Status,用于描述 CPU 的执行状态。当某个 CPU 正在访问 RCU 保护的临界区时,认为是活动的状态,而当它离开了临界区后,则认为它是静止的状态。当所有的 CPU 都至少经历过一次 Quiescent Status 后,宽限期将结束并触发回收工作。
因为 rcu_read_lock 和 rcu_read_unlock 分别是关闭抢占和打开抢占,如下所示:
staticinlinevoid__rcu_read_lock(void){preempt_disable();}
staticinlinevoid__rcu_read_unlock(void){preempt_enable();}
所以发生抢占,就说明不在 rcu_read_lock 和 rcu_read_unlock 之间,即已经完成访问或者还未开始访问。
Linux 同步方式的总结
资料免费领
学习直通车
Ⅱ 如何在加载模块时向模块传递参数值
1. 现象描述
Linux系统中,动态加载的模块往往需要实现:
1)在加载模块时,向模块传递一个参数值,且该参数值在模块运行过程中不能对其进行修改;
2)在加载模块时,向模块传递一个参数值,且该参数值在模块运行过程中根据需求对其进行动态修改。
2. 关键过程
1、Linux系统2.6内核下,可以通过宏mole_param(name, type, perm)将参数name声明为模块参数,该参数值可以在加载模块时指定,否则为模块内定义的缺省值;
2、我们需要关注perm,perm表示此参数在sysfs文件系统中所对应的文件节点的属性:
1)当perm为0时,表示此参数不存在在sysfs文件系统下对应的文件节点;
2)模块被加载后,在/sys/mole/目录下将出现以此模块名命名的目录;
3)如果此模块存在perm不为0的命令行参数,在此模块的目录下将出现parameters目录,包含一系列以参数命名的文件节点;
4)这些文件的权限值等于perm,文件的内容为参数的值。
3、perm有四种不同属性的模块参数:
1)可读写参数:此参数可以实时查看和动态修改其值;其属性为S_IRUGO|S_IWUSR;
2)可读参数:此参数只能实时查看,不能动态修改;其属性为S_IRUGO;
3)可写参数:此参数不能实时查看,但可以动态修改;其属性为S_IWUSR;
4)不可读写参数:此参数不能在sysfs文件系统中显示,也不能实时查看和动态修改其值;其属性值为0;
由此我们可以通过设置不同的perm值,实现不同参数不同的控制。
3. 案例实现
3.1. Demo说明
1、demo程序定义了2各模块参数,分别为uid、period。加载模块时,可以向模块传递这两个参数的值,否则这两个参数值将为默认值;模块运行过程中,两者均可被用户、用户所在组及其他组读取,后者还可被用户修改。
2、demo程序使用到的perm权限值含义:
S_IRUGO:S_IRUSR|S_IRGRP|S_IROTH,表示可以被用户、用户所在组及其他组读取且只读;
S_IWUSR:表示可以被用户(能动态加载模块的用户必须是超级用户)修改。
3、demo程序根据uid和period打印不同的信息;当period值变化时,会再次打印信息。
4、demo程序使用说明如下:
1)加载模块时:insmod demo.ko uid=0 period =0
2)模块运行过程中,读取uid值:cat /sys/mole/demo/parameters/uid
3) 模块运行过程中,修改period值:echo 1 > /sys/mole/demo/parameters/period
3.2. 源文件
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/blkdev.h>
#include <linux/list.h>
#include <linux/timer.h>
#include <linux/version.h>
#include <linux/moleparam.h>
#include <linux/device.h>
#include <linux/mole.h>
#include <linux/string.h>
#include <linux/dma-mapping.h>
#include <asm/semaphore.h>
#include <asm/page.h>
typedef uint8_t bool_t;
#define MORNING 0
#define AFTERNOON 1
#define EVENING 2
#define UNKNOWN 3
#define FALSE 0
#define TRUE 1
#define USER_NUM 3
/******** mole information ***************/
MODULE_AUTHOR("H3C Corporation");
MODULE_DESCRIPTION("Demo function");
MODULE_LICENSE("GPL");
/******** mole parameters ***************/
static uint uid = 0;
mole_param(uid, uint, S_IRUGO);
static uint period = MORNING;
mole_param(period, uint, S_IRUGO|S_IWUSR);
/******** global parameters ***************/
char user_name[USER_NUM][20] = {{"wuwu"}, {"pikaqiu"}, {"lala"}};
uint prev_period = UNKNOWN;
bool_t demo_quit = FALSE;
struct completion com_demo;
int demo_thread(void* unuse)
{
daemonize("demo_thread");
for(;;)
{
if(demo_quit)
{
break;
}
if(prev_period != period)
{
if(MORNING == period)
{
printk(KERN_EMERG "Good morning, %s/n", user_name[uid]);
}
else if(AFTERNOON == period)
{
printk(KERN_EMERG "Good afternoon, %s/n", user_name[uid]);
}
else if(EVENING == period)
{
printk(KERN_EMERG "Good evening, %s/n", user_name[uid]);
}
else
{
printk(KERN_EMERG "Parameter period is invalid! Please choose from follows:/n");
printk(KERN_EMERG "0: means morning/n");
printk(KERN_EMERG "1: means afternoon/n");
printk(KERN_EMERG "2: means evening/n");
printk(KERN_EMERG "/n");
}
prev_period = period;
}
msleep(10);
}
complete_and_exit(&com_demo, 0);
}
static int __init demo_init(void)
{
pid_t pid = 0;
uint32_t i = 0;
if(uid >= USER_NUM)
{
printk(KERN_EMERG "Parameter uid is invalid, please choose from follows:/n");
for(i=0; i<USER_NUM; i++)
{
printk(KERN_EMERG "i: named %s/n", user_name[i]);
}
printk(KERN_EMERG "/n");
return -1;
}
init_completion(&com_demo);
pid = kernel_thread(demo_thread, NULL, CLONE_KERNEL);
if(pid < 0)
{
printk(KERN_EMERG "demo thread create failed!/n");
return -1;
}
printk(KERN_EMERG "Welcome to the demo!/n");
return 0;
}
static void __exit demo_exit(void)
{
demo_quit = TRUE;
wait_for_completion(&com_demo);
printk(KERN_EMERG "Byebye, %s/n", user_name[uid]);
return;
}
mole_init(demo_init);
mole_exit(demo_exit);
4. 经验总结
1、根据对不同用户权限要求设置perm位;
2、对于只需在加载模块时传递参数值、而不希望用户看到该参数,建议将perm位置为0。
Ⅲ linux中如何实现sleep(0)的功能
linux下的sleep(0),有些时候被实现为下面这样:
unsigned int sleep (unsigned int seconds)
{
……
/* This is not necessary but some buggy programs depend on this. */
if (seconds == 0)
return 0;
……
}
如果你的程序对实时性要求不那么高,可以使用usleep(1),不然就只能用信号或者其他事件机制了。
Ⅳ qt界面不动,但是响应事件
无响应情况的发生与QT版本(本noob使用的Qt Creator 4.8.0 (Enterprise))无关,在QT使用时突然发作。
表现为内存占用不断上升,直至到达内存上限后QT闪退123
结合广大博友的相似案例,以及自己成功的解决方案,初步判断为QT无响应和显卡/显示驱动/其他软件的进程干涉有关。
解决方案
显卡问题
运行QtCreator的时候不支持某些显卡或者不支持高性能图形处理器
方法1(笔记本适用,台式PC可能不行)
你使用的独立显卡有可能不兼容QT,首选图形处理器选择为自动选择或者集成图形
引用来自https://blog.csdn.net/Hxj_CSDN/article/details/80630420的图片
方法2(适用不存在上述方法的首选图形处理器选项的台式PC)
inter i系列cpu自带集成显示处理。所以直接禁用独立显卡便可以切换成集成图形。
在这里插入图片描述
显卡驱动原因
想一想最近有没有更新显卡驱动或者安装NVIDIA相关驱动(如 3D vision)
将其卸载安装旧稳定版本显卡驱动,或者卸载3D vision
其他软件进程的干涉(如HOOK)
已知有道词典的划词取词功能(可能是用了信息钩子)会导致QT无响应的BUG。
1还有可能是上层屏幕显示的软件导致QT无响应。
请尽量关闭其他软件进程,再重新进入QT排除原因。如果实锤了,那当然就不能同时使用了!
其他可能的解决办法
删除 ~\AppData\Roaming\QtProject文件夹,然后再打开Qt Creator即可。
该文件夹经本noob的试验是用于存储QT个人设置以及历史项目目录等文件的,大可删除,QT会在重新打开时自动生成,只不过你相关的设置就会恢复默认值了!!!
Linux下,~是/home/YourUserName
Windows下,~是C:\Users\YourUserName
Ⅳ 请问在linux下的红外接口如何驱动
延时一般两种,mdelay这种忙等待的,多少大体就是多少,msleep这种调度的,多少就不是多少,因为里面有个调度时间。你可以自己用示波器抓一下时间就知道了。
Ⅵ qt sleep函数哪个头文件
QT虽然没有提供Sleep(),但是QT提供了系统调用,然而每个系统中都有Sleep()函数,所以可以简单的包含系统头文件即可。
如果是windows平台则:
#include <windows.h>
就可以用Sleep()了:
Sleep(10000);
(注意是大写S)linux下头文件是:
#include <sys/stat.h>
Ⅶ 在system-top.dts中描述USB设备
1. 开机后,usb功能正常初始化;这时插入usb的U盘,或者hub;则首先调用如下代码。
static int hcd_pci_runtime_resume(struct device *dev){ int retval; powermac_set_asic(to_pci_dev(dev), 1); retval = resume_common(dev, PM_EVENT_AUTO_RESUME); dev_dbg(dev, "hcd_pci_runtime_resume: %d\n", retval); return retval;}
然后继续调用:
static int resume_common(struct device *dev, int event){ struct pci_dev *pci_dev = to_pci_dev(dev); struct usb_hcd *hcd = pci_get_drvdata(pci_dev); int retval; if (HCD_RH_RUNNING(hcd) || (hcd->shared_hcd && HCD_RH_RUNNING(hcd->shared_hcd))) { dev_dbg(dev, "can't resume, not suspended!\n"); return 0; } retval = pci_enable_device(pci_dev); if (retval < 0) { dev_err(dev, "can't re-enable after resume, %d!\n", retval); return retval; } pci_set_master(pci_dev); if (hcd->driver->pci_resume && !HCD_DEAD(hcd)) { /* * Only EHCI controllers have to wait for their companions. * No locking is needed because PCI controller drivers do not * get unbound ring system resume. */ if (pci_dev->class == CL_EHCI && event != PM_EVENT_AUTO_RESUME) for_each_companion(pci_dev, hcd, ehci_wait_for_companions); retval = hcd->driver->pci_resume(hcd, event == PM_EVENT_RESTORE); if (retval) { dev_err(dev, "PCI post-resume error %d!\n", retval); if (hcd->shared_hcd) usb_hc_died(hcd->shared_hcd); usb_hc_died(hcd); } } return retval;}
在 代码 hcd->driver->pci_resume() 里, 调用函数如下:
static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated){ struct xhci_hcd *xhci = hcd_to_xhci(hcd); struct pci_dev *pdev = to_pci_dev(hcd->self.controller); int retval = 0; /* Due to one HW bug, XHCI will keep generating PME wakeups and fail * to stay in runtime suspended state, so required to clear the internal * PME flag once it is back to D0 as the software workaround */ if (xhci->quirks & XHCI_SPURIOUS_PME) { xhci_intel_clr_internal_pme_flag(xhci); xhci_intel_ssic_port_unused(xhci, 0); } /* The BIOS on systems with the Intel Panther Point chipset may or may * not support xHCI natively. That means that ring system resume, it * may switch the ports back to EHCI so that users can use their * keyboard to select a kernel from GRUB after resume from hibernate. * * The BIOS is supposed to remember whether the OS had xHCI ports * enabled before resume, and switch the ports back to xHCI when the * BIOS/OS semaphore is written, but we all know we can't trust BIOS * writers. * * Unconditionally switch the ports back to xHCI after a system resume. * It should not matter whether the EHCI or xHCI controller is * resumed first. It's enough to do the switchover in xHCI because * USB core won't notice anything as the hub driver doesn't start * running again until after all the devices (including both EHCI and * xHCI host controllers) have been resumed. */ if (pdev->vendor == PCI_VENDOR_ID_INTEL) usb_enable_intel_xhci_ports(pdev); retval = xhci_resume(xhci, hibernated); return retval;}
然后调用函数,xhci_resume();
int xhci_resume(struct xhci_hcd *xhci, bool hibernated){ u32 command, temp = 0, status; struct usb_hcd *hcd = xhci_to_hcd(xhci); struct usb_hcd *secondary_hcd; int retval = 0; bool comp_timer_running = false; pr_info("wgq[%s-%d] hibernated[%d]\n",__func__,__LINE__,hibernated); /* Wait a bit if either of the roothubs need to settle from the * transition into bus suspend. */ if (time_before(jiffies, xhci->bus_state[0].next_statechange) || time_before(jiffies, xhci->bus_state[1].next_statechange)) msleep(100); set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); set_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags); spin_lock_irq(&xhci->lock); if (xhci->quirks & XHCI_RESET_ON_RESUME) hibernated = true; if (!hibernated) { /* step 1: restore register */ xhci_restore_registers(xhci); /* step 2: initialize command ring buffer */ xhci_set_cmd_ring_deq(xhci); /* step 3: restore state and start state*/ /* step 3: set CRS flag */ command = readl(&xhci->op_regs->command); command |= CMD_CRS; writel(command, &xhci->op_regs->command); if (xhci_handshake(xhci, &xhci->op_regs->status, STS_RESTORE, 0, 10 * 1000)) { xhci_warn(xhci, "WARN: xHC restore state timeout\n"); spin_unlock_irq(&xhci->lock); return -ETIMEDOUT; } temp = readl(&xhci->op_regs->status); } /* If restore operation fails, re-initialize the HC ring resume */ if ((temp & STS_SRE) || hibernated) { if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) && !(xhci_all_ports_seen_u0(xhci))) { del_timer_sync(&xhci->comp_mode_recovery_timer); xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, "Compliance Mode Recovery Timer deleted!"); } /* Let the USB core know _both_ roothubs lost power. */ usb_root_hub_lost_power(xhci->main_hcd->self.root_hub); usb_root_hub_lost_power(xhci->shared_hcd->self.root_hub); xhci_dbg(xhci, "Stop HCD\n"); xhci_halt(xhci); xhci_reset(xhci); spin_unlock_irq(&xhci->lock); xhci_cleanup_msix(xhci); xhci_dbg(xhci, "// Disabling event ring interrupts\n"); temp = readl(&xhci->op_regs->status); writel(temp & ~STS_EINT, &xhci->op_regs->status); temp = readl(&xhci->ir_set->irq_pending); writel(ER_IRQ_DISABLE(temp), &xhci->ir_set->irq_pending); xhci_print_ir_set(xhci, 0); xhci_dbg(xhci, "cleaning up memory\n"); xhci_mem_cleanup(xhci); xhci_dbg(xhci, "xhci_stop completed - status = %x\n", readl(&xhci->op_regs->status)); /* USB core calls the PCI reinit and start functions twice: * first with the primary HCD, and then with the secondary HCD. * If we don't do the same, the host will never be started. */ if (!usb_hcd_is_primary_hcd(hcd)) secondary_hcd = hcd; else secondary_hcd = xhci->shared_hcd; xhci_dbg(xhci, "Initialize the xhci_hcd\n"); retval = xhci_init(hcd->primary_hcd); if (retval) return retval; comp_timer_running = true; xhci_dbg(xhci, "Start the primary HCD\n"); retval = xhci_run(hcd->primary_hcd); if (!retval) { xhci_dbg(xhci, "Start the secondary HCD\n"); retval = xhci_run(secondary_hcd); } hcd->state = HC_STATE_SUSPENDED; xhci->shared_hcd->state = HC_STATE_SUSPENDED; goto done; } /* step 4: set Run/Stop bit */ command = readl(&xhci->op_regs->command); command |= CMD_RUN; writel(command, &xhci->op_regs->command); xhci_handshake(xhci, &xhci->op_regs->status, STS_HALT, 0, 250 * 1000); xhci_resume_pending_ports(xhci); /* step 5: walk topology and initialize portsc, * portpmsc and portli */ /* this is done in bus_resume */ /* step 6: restart each of the previously * Running endpoints by ringing their doorbells */ spin_unlock_irq(&xhci->lock);done: if (retval == 0) { /* Resume root hubs only when have pending events. */ status = readl(&xhci->op_regs->status); if (status & STS_EINT) { usb_hcd_resume_root_hub(hcd); usb_hcd_resume_root_hub(xhci->shared_hcd); } } /* * If system is subject to the Quirk, Compliance Mode Timer needs to * be re-initialized Always after a system resume. Ports are subject * to suffer the Compliance Mode issue again. It doesn't matter if * ports have entered previously to U0 before system's suspension. */ if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) && !comp_timer_running) compliance_mode_recovery_timer_init(xhci); /* Re-enable port polling. */ xhci_dbg(xhci, "%s: starting port polling.\n", __func__); set_bit(HCD_FLAG_POLL_RH, &hcd->flags); usb_hcd_poll_rh_status(hcd); return retval;}
Ⅷ linux内核中mdelay怎么实现
1.udelay(); mdelay(); ndelay();实现的原理本质上都是忙等待,ndelay和mdelay都是通过udelay衍生出来的,我们使用这些函数的实现往往会碰到编译器的警告implicit declaration of function'udelay',这往往是由于头文件的使用不当造成的。在include/asm-???/delay.h中定义了udelay(),而在include/linux/delay.h中定义了mdelay和ndelay. udelay一般适用于一个比较小的delay,如果你填的数大于2000,系统会认为你这个是一个错误的delay函数,因此如果需要2ms以上的delay需要使用mdelay函数。 2.由于这些delay函数本质上都是忙等待,对于长时间的忙等待意味这无谓的耗费着cpu的资源,因此对于毫秒级的延时,内核提供了msleep,ssleep等函数,这些函数将使得调用它的进程睡眠参数指定的时间。 应用层: #include <unistd.h> 1、unsigned int sleep(unsigned int seconds); 秒级 2、int usleep(useconds_t usec); 微秒级:1/10^-6 #define _POSIX_C_SOURCE 199309 #include <time.h> 3、int nanosleep(const struct timespec *req, struct timespec *rem); struct timespec { time_t tv_sec; /* seconds */ long tv_nsec; /* nanoseconds */ }; // The value of the nanoseconds field must be in the range 0 to 999999999. 内核层: include <linux/delay.h> 1、void ndelay(unsigned long nsecs); 纳秒级:1/10^-10 2、void udelay(unsigned long usecs); 微秒级: 1/10^-6 3、void mdelay(unsigned long msecs); 毫秒级:1/10^-3 sleep_on(), interruptible_sleep_on(); sleep_on_timeout(), interruptible_sleep_on_timeout(); 根据你的情况选用这些函数,注意: sleep操作在kernel必须小心、小心。。。 udelay()等函数是cpu忙等,没有传统意义上的sleep。这些函数相当于我们平时的阻塞读、写之类的语义,主要用于等外设完成某些操作Ⅸ linux内核编程能不能使用sleep函数,有没有代替的方法
没有sleep
常用用jiffies、ndelay、mdelay等
msleep和ssleep不可中断。很少见。