导航:首页 > 编程系统 > linuxsuspended

linuxsuspended

发布时间:2023-02-08 06:26:58

A. linux触摸屏驱动中什么时候会调用suspend这个函数

android系统摁下电源键后会让系统进入休眠以达到节电的目的。内核驱动中和休眠相关的就是suspend和resume函数。

suspend函数用于休眠,resume函数用于唤醒。下面分析驱动中的这两个函数是如何被调用到的。

驱动部分:

首先需要分析驱动的注册过程,较新的内核都是采用DTS方式来取代在内核中直接定义platform_device数据结构的注册方式,本文是基于DTS机制的内核来分析。

proct对应的dts文件在编译时被编译为dtb文件,uboot在启动时候会将其地址传给内核,内核在启动过程中会去解析,具体解析是在start_kernel()->setup_arch() --> unflatten_device_tree()中具体分析可以参考网上,解析的最终结果会存放在allnodes地址处,这个allnodes随后在machine的init函数
中被使用,init函数中会根据allnodes中的节点数据组合成platform_device数据结构,然后将其注册到platform总线上,下面简要分析一下并重点关注这些初始化过程中和
pm相关的初始化。

我参与的项目中machine的init函数就是via_init_machine函数,在这个函数中就是调用了of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL)这个函数来解析allnodes的。of_platform_populate是系统提供的接口。下面分析这个接口的实现:

[html] view plain
int of_platform_populate(struct device_node *root,
const struct of_device_id *matches,
const struct of_dev_auxdata *lookup,
struct device *parent)
{
struct device_node *child;
int rc = 0;

root = root ? of_node_get(root) : of_find_node_by_path("/");
if (!root)
return -EINVAL;

for_each_child_of_node(root, child) {
rc = of_platform_bus_create(child, matches, lookup, parent, true);
if (rc)
break;
}

of_node_put(root);
return rc;
}
root最后就是取到的根节点,然后其作为参数传递给of_platform_bus_create,of_platform_device_create_pdata的实现如下:

[html] view plain
static int of_platform_bus_create(struct device_node *bus,
const struct of_device_id *matches,
const struct of_dev_auxdata *lookup,
struct device *parent, bool strict)
{
const struct of_dev_auxdata *auxdata;
struct device_node *child;
struct platform_device *dev;
const char *bus_id = NULL;
void *platform_data = NULL;
int rc = 0;

/* Make sure it has a compatible property */
if (strict && (!of_get_property(bus, "compatible", NULL))) {
pr_debug("%s() - skipping %s, no compatible prop\n",
__func__, bus->full_name);
return 0;
}

auxdata = of_dev_lookup(lookup, bus);
if (auxdata) {
bus_id = auxdata->name;
platform_data = auxdata->platform_data;
}

if (of_device_is_compatible(bus, "arm,primecell")) {
of_amba_device_create(bus, bus_id, platform_data, parent);
return 0;
}

dev = of_platform_device_create_pdata(bus, bus_id, platform_data, parent);
if (!dev || !of_match_node(matches, bus))
return 0;

for_each_child_of_node(bus, child) {
pr_debug(" create child: %s\n", child->full_name);
rc = of_platform_bus_create(child, matches, lookup, &dev->dev, strict);
if (rc) {
of_node_put(child);
break;
}
}
return rc;
}
根据传入参数,我们这里直接分析of_platform_device_create_padate函数,如下:

[html] view plain
struct platform_device *of_platform_device_create_pdata(
struct device_node *np,
const char *bus_id,
void *platform_data,
struct device *parent)
{
struct platform_device *dev;

if (!of_device_is_available(np))
return NULL;

dev = of_device_alloc(np, bus_id, parent);
if (!dev)
return NULL;

#if defined(CONFIG_MICROBLAZE)
dev->archdata.dma_mask = 0xffffffffUL;
#endif
dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
dev->dev.bus = &platform_bus_type;
dev->dev.platform_data = platform_data;

/* We do not fill the DMA ops for platform devices by default.
* This is currently the responsibility of the platform code
* to do such, possibly using a device notifier
*/

if (of_device_add(dev) != 0) {
platform_device_put(dev);
return NULL;
}

return dev;
}

of_platform_device_create_padate->of_device_alloc->platform_device_alloc

便在platform_device_alloc函数中进行进行alloc和初始化了,实现如下:

[html] view plain
struct platform_device *platform_device_alloc(const char *name, int id)
{
struct platform_object *pa;

pa = kzalloc(sizeof(struct platform_object) + strlen(name), GFP_KERNEL);
if (pa) {
strcpy(pa->name, name);
pa->pdev.name = pa->name;
pa->pdev.id = id;
device_initialize(&pa->pdev.dev);
pa->pdev.dev.release = platform_device_release;
arch_setup_pdev_archdata(&pa->pdev);
}

return pa ? &pa->pdev : NULL;
}
可以看到有个device_initialize,这里面对pdev.dev做一些列的初始化,其中有一个函数就是device_pm_init,这个函数就是我们一直关心的device相关的pm函数,具体实现如下:

[html] view plain
void device_pm_init(struct device *dev)
{
dev->power.is_prepared = false;
dev->power.is_suspended = false;
init_completion(&dev->power.completion);
complete_all(&dev->power.completion);
dev->power.wakeup = NULL;
spin_lock_init(&dev->power.lock);
pm_runtime_init(dev);
INIT_LIST_HEAD(&dev->power.entry);
dev->power.power_state = PMSG_INVALID;
}

可以看见它对device和功耗相关的数据做了一些初始化,我们这里先重点关注下dev->power.entry,初始化一个链表头,所以他/它很有可能会在后面加到某个链表里面去,而那个链表应该是用来保存所有的device用的。系统中所有的platform_device都是通过这种方式注册到系统中的,那么应该所有的platform_device都会初始化一个dev->power.entry,如果到时候把所有的dev->power.entry都添加到某个链表上去,那么系统到时候查询的时候只要找到这个list head就可以找到所有的platform_device了。嗯,不过这是我们的猜测。我们接下去分析来验证下。

platform_device通过alloc之后已经初始化好了,那么接下去就可以添加到系统中了,所以我们再回头看of_platform_device_create_pdata的实现。
函数在of_device_alloc之后把dev->dev.bus赋值给了platform_bus_type,接着就调用了of_device_add函数,在of_device_add函数中最后通过device_add添加到了bus上,但是device_add中有个函数需要我们关系,就是device_pm_add(dev),实现如下:

[html] view plain
void device_pm_add(struct device *dev)
{
pr_debug("PM: Adding info for %s:%s\n",
dev->bus ? dev->bus->name : "No Bus", dev_name(dev));
mutex_lock(&dpm_list_mtx);
if (dev->parent && dev->parent->power.is_prepared)
dev_warn(dev, "parent %s should not be sleeping\n",
dev_name(dev->parent));
list_add_tail(&dev->power.entry, &dpm_list);
dev_pm_qos_constraints_init(dev);
mutex_unlock(&dpm_list_mtx);
}

可以看到这里list_add_tail(&dev->power.entry, &dpm_list);这就验证了我们之前的猜测。所有注册到系统中的设备,最终都是会添加到dpm_list这条链表上。

那么系统在休眠的时候是如何通过dmp_list这表链表来suspend设备的呢?接下去就是我们要分析的电源管理部分内容。

系统电源部分:
电源管理相关文件在kernel/power目录下,前面已经分析到。系统中注册的设备都是会添加到dmp_list这条链表上的。那么睡眠的时候系统应该是会查找dmp_list这条链表,
然后通过这条链表依次去查到对应的driver,然后调用driver中的suspend方法。下面我们来验证。

2.在suspend会轮询bus下的driver,然后一次调用到driver->pm->suspend方法,然后进入休眠。

3.state_store->pm_suspend->enter_state->suspend_devices_and_enter->dpm_suspend_start->dpm_suspend->device_suspend->__device_suspend->pm_op->(ops->suspend)

B. linux执行命令停止无限弹

linux执行命令停止无限弹如下
先来写一个需要一直运行的程序,比如 Flask 版的 Hello World$ vi hello.pyfrom flask import Flaskapp = Flask(__name__)pp.route('/') index():return hello world'if __name__ == '__main__':app.run(host=Ɔ.0.0.0') pip install flask$ python hello.p启动成功控制台提示:* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)此时打开浏览器访问 http://你的服务器ip:5000 即可看到 Hello World 了按 CTRL+C 退出,如果想让程序一直运行又想同时做其他事怎么办?
CTRL+Z 暂停程序程序在前台运行时,按下 CRTL+Z, 程序进入暂停状态[1] + 74237 suspended python hello.py此时你又可以在终端下敲其他命令了。但刷新浏览器,长时间没有响应,因为程序进入暂停状态了。jobs 列出后台运行的命$ jobs[1] - suspended python hello.py
再来启动一个命令,比如$ tail -f hello.py然后 CTRL+Z 暂停,再运行下 jobs 命令前面的[1] [2] 是任务编号,+ - 和接下来要说的 fg、bg 命令有关,suspended 那一栏表示状态,剩下的就是命令
要把一个程序放在后台运行,照上面的做法,得先运行,然后 CTRL+Z 暂停,再用 bg 命令放到后台运行。使用 & 来简化这一过程,并且使用 > 来重定向后台运行的程序在终端上的输出。

C. org.apache.catalina.startup.Bootstrap at localhost:50973

LDD(Linux Device Driver)第三章scull设备例子的时候,也遇到了相似的问题,后来发现是经make编译出来的scull.ko的owner和group属性不对,而一开始学习第二章hello world的时候却没有遇到这个问题,尝试着chown和chgrp之后(own和group都改成root),就能够顺利地用insmod加载该模块进内核了。

D. linux开机自动执行命令和脚本 自动启动 自启 进程一直运行

原文及更新: https://neucrack.com/p/91

直接在/etc/rc.local(/etc/rc.d/rc.local)文件中添加即可

上面这脚本实际上在使用时出现了问题, /home/neucrack/software/ss/start_ss_local.sh 这个命令始终没有被执行,原因是 /home/neucrack/software/ss/start_kcptun_client.sh 中的命令阻塞了进程,导致后面一句始终没有执行,可以将他们分别放到后台执行就行了,如何在后台执行可以看文章最后一部分

也可以自己手动在rc*.d中建立软连接

桌面系统搜索 启动 ,打开启动管理器 添加删除即可

一般有以下几种方法:
1)在输入命令的最前面加上 nohup 命令
如 nohup your_command & 这样命令在你退出后仍然会在后台执行
2) setsid 命令
setsid your_command 该命令的结果是使你所运行的命令的父进程为init,所以只有关机该进程才会停止
3) (your_command &)
就是用括号将你的命令括起来,这样做也是使命令的父进程为init
4) disown
当你在命令行下输入 your_command & 后命令就在后台执行了,然后执行jobs命令,该命令会列出当前正在后台执行的命令。例如输入命令“top&”
然后执行"jobs"
输出结果是
[1] + Suspended (tty output) top
注意行开头方括号内的数字,该数字叫做jobspec,是给当前后台运行的job的编号。这是你只要在命令行下输入"disown -h 1" 后台运行的top命令就不会受到hangup信号的影响了。
5)使用 screen 命令
在命令行下输入screen命令就开启了一个screen进程,它就好像是一个全新的命令运行环境,在该环境中你可以像在正常的terminal下那样执行
命令,但是这个screen是不受其父进程的hangup信号的影响的,既然screen不受其父进程影响,当你意外掉线或者退出系统时,在screen
中仍在执行的命令仍然会继续执行。关于screen命令的使用方法你可以再去查阅相关资料。

E. 怎样写linux下的USB设备驱动程序

写一个USB的驱动程序最 基本的要做四件事:驱动程序要支持的设备、注册USB驱动程序、探测和断开、提交和控制urb(USB请求块)
驱动程序支持的设备:有一个结构体struct usb_device_id,这个结构体提供了一列不同类型的该驱动程序支持的USB设备,对于一个只控制一个特定的USB设备的驱动程序来说,struct usb_device_id表被定义为:
/* 驱动程序支持的设备列表 */
static struct usb_device_id skel_table [] = {
{ USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },
{ } /* 终止入口 */
};
MODULE_DEVICE_TABLE (usb, skel_table);
对 于PC驱动程序,MODULE_DEVICE_TABLE是必需的,而且usb必需为该宏的第一个值,而USB_SKEL_VENDOR_ID和 USB_SKEL_PRODUCT_ID就是这个特殊设备的制造商和产品的ID了,我们在程序中把定义的值改为我们这款USB的,如:
/* 定义制造商和产品的ID号 */
#define USB_SKEL_VENDOR_ID 0x1234
#define USB_SKEL_PRODUCT_ID 0x2345
这两个值可以通过命令lsusb,当然你得先把USB设备先插到主机上了。或者查看厂商的USB设备的手册也能得到,在我机器上运行lsusb是这样的结果:
Bus 004 Device 001: ID 0000:0000
Bus 003 Device 002: ID 1234:2345 Abc Corp.
Bus 002 Device 001: ID 0000:0000
Bus 001 Device 001: ID 0000:0000
得到这两个值后把它定义到程序里就可以了。
注册USB驱动程序:所 有的USB驱动程序都必须创建的结构体是struct usb_driver。这个结构体必须由USB驱动程序来填写,包括许多回调函数和变量,它们向USB核心代码描述USB驱动程序。创建一个有效的 struct usb_driver结构体,只须要初始化五个字段就可以了,在框架程序中是这样的:
static struct usb_driver skel_driver = {
.owner = THIS_MODULE,
.name = "skeleton",
.probe = skel_probe,
.disconnect = skel_disconnect,
.id_table = skel_table,
};
探测和断开:当 一个设备被安装而USB核心认为该驱动程序应该处理时,探测函数被调用,探测函数检查传递给它的设备信息,确定驱动程序是否真的适合该设备。当驱动程序因 为某种原因不应该控制设备时,断开函数被调用,它可以做一些清理工作。探测回调函数中,USB驱动程序初始化任何可能用于控制USB设备的局部结构体,它 还把所需的任何设备相关信息保存到一个局部结构体中,
提交和控制urb:当驱动程序有数据要发送到USB设备时(大多数情况是在驱动程序的写函数中),要分配一个urb来把数据传输给设备:
/* 创建一个urb,并且给它分配一个缓存*/
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb) {
retval = -ENOMEM;
goto error;
}
当urb被成功分配后,还要创建一个DMA缓冲区来以高效的方式发送数据到设备,传递给驱动程序的数据要复制到这块缓冲中去:
buf = usb_buffer_alloc(dev->udev, count, GFP_KERNEL, &urb->transfer_dma);
if (!buf) {
retval = -ENOMEM;
goto error;
}

if (_from_user(buf, user_buffer, count)) {
retval = -EFAULT;
goto error;
}
当数据从用户空间正确复制到局部缓冲区后,urb必须在可以被提交给USB核心之前被正确初始化:
/* 初始化urb */
usb_fill_bulk_urb(urb, dev->udev,
usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
buf, count, skel_write_bulk_callback, dev);
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
然后urb就可以被提交给USB核心以传输到设备了:
/* 把数据从批量OUT端口发出 */
retval = usb_submit_urb(urb, GFP_KERNEL);
if (retval) {
err("%s - failed submitting write urb, error %d", __FUNCTION__, retval);
goto error;
}
当urb被成功传输到USB设备之后,urb回调函数将被USB核心调用,在我们的例子中,我们初始化urb,使它指向skel_write_bulk_callback函数,以下就是该函数:
static void skel_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
{
struct usb_skel *dev;

dev = (struct usb_skel *)urb->context;

if (urb->status &&
!(urb->status == -ENOENT ||
urb->status == -ECONNRESET ||
urb->status == -ESHUTDOWN)) {
dbg("%s - nonzero write bulk status received: %d",
__FUNCTION__, urb->status);
}

/* 释放已分配的缓冲区 */
usb_buffer_free(urb->dev, urb->transfer_buffer_length,
urb->transfer_buffer, urb->transfer_dma);
}
有时候USB驱动程序只是要发送或者接收一些简单的数据,驱动程序也可以不用urb来进行数据的传输,这是里涉及到两个简单的接口函数:usb_bulk_msg和usb_control_msg ,在这个USB框架程序里读操作就是这样的一个应用:
/* 进行阻塞的批量读以从设备获取数据 */
retval = usb_bulk_msg(dev->udev,
usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr),
dev->bulk_in_buffer,
min(dev->bulk_in_size, count),
&count, HZ*10);

/*如果读成功,复制到用户空间 */
if (!retval) {
if (_to_user(buffer, dev->bulk_in_buffer, count))
retval = -EFAULT;
else
retval = count;
}
usb_bulk_msg接口函数的定义如下:
int usb_bulk_msg(struct usb_device *usb_dev,unsigned int pipe,
void *data,int len,int *actual_length,int timeout);
其参数为:
struct usb_device *usb_dev:指向批量消息所发送的目标USB设备指针。
unsigned int pipe:批量消息所发送目标USB设备的特定端点,此值是调用usb_sndbulkpipe或者usb_rcvbulkpipe来创建的。
void *data:如果是一个OUT端点,它是指向即将发送到设备的数据的指针。如果是IN端点,它是指向从设备读取的数据应该存放的位置的指针。
int len:data参数所指缓冲区的大小。
int *actual_length:指向保存实际传输字节数的位置的指针,至于是传输到设备还是从设备接收取决于端点的方向。
int timeout:以Jiffies为单位的等待的超时时间,如果该值为0,该函数一直等待消息的结束。
如果该接口函数调用成功,返回值为0,否则返回一个负的错误值。
usb_control_msg接口函数定义如下:
int usb_control_msg(struct usb_device *dev,unsigned int pipe,__u8 request,__u8requesttype,__u16 value,__u16 index,void *data,__u16 size,int timeout)
除了允许驱动程序发送和接收USB控制消息之外,usb_control_msg函数的运作和usb_bulk_msg函数类似,其参数和usb_bulk_msg的参数有几个重要区别:
struct usb_device *dev:指向控制消息所发送的目标USB设备的指针。
unsigned int pipe:控制消息所发送的目标USB设备的特定端点,该值是调用usb_sndctrlpipe或usb_rcvctrlpipe来创建的。
__u8 request:控制消息的USB请求值。
__u8 requesttype:控制消息的USB请求类型值。
__u16 value:控制消息的USB消息值。
__u16 index:控制消息的USB消息索引值。
void *data:如果是一个OUT端点,它是指身即将发送到设备的数据的指针。如果是一个IN端点,它是指向从设备读取的数据应该存放的位置的指针。
__u16 size:data参数所指缓冲区的大小。
int timeout:以Jiffies为单位的应该等待的超时时间,如果为0,该函数将一直等待消息结束。
如果该接口函数调用成功,返回传输到设备或者从设备读取的字节数;如果不成功它返回一个负的错误值。
这两个接口函数都不能在一个中断上下文中或者持有自旋锁的情况下调用,同样,该函数也不能被任何其它函数取消,使用时要谨慎。
我们要给未知的USB设备写驱动程序,只需要把这个框架程序稍做修改就可以用了,前面我们已经说过要修改制造商和产品的ID号,把0xfff0这两个值改为未知USB的ID号。
#define USB_SKEL_VENDOR_ID 0xfff0
#define USB_SKEL_PRODUCT_ID 0xfff0
还 有就是在探测函数中把需要探测的接口端点类型写好,在这个框架程序中只探测了批量(USB_ENDPOINT_XFER_BULK)IN和OUT端点,可 以在此处使用掩码(USB_ENDPOINT_XFERTYPE_MASK)让其探测其它的端点类型,驱动程序会对USB设备的每一个接口进行一次探测, 当探测成功后,驱动程序就被绑定到这个接口上。再有就是urb的初始化问题,如果你只写简单的USB驱动,这块不用多加考虑,框架程序里的东西已经够用 了,这里我们简单介绍三个初始化urb的辅助函数:
usb_fill_int_urb :它的函数原型是这样的:
void usb_fill_int_urb(struct urb *urb,struct usb_device *dev,
unsigned int pipe,void *transfer_buff,
int buffer_length,usb_complete_t complete,
void *context,int interval);
这个函数用来正确的初始化即将被发送到USB设备的中断端点的urb。
usb_fill_bulk_urb :它的函数原型是这样的:
void usb_fill_bulk_urb(struct urb *urb,struct usb_device *dev,
unsigned int pipe,void *transfer_buffer,
int buffer_length,usb_complete_t complete)
这个函数是用来正确的初始化批量urb端点的。
usb_fill_control_urb :它的函数原型是这样的:
void usb_fill_control_urb(struct urb *urb,struct usb_device *dev,unsigned int pipe,unsigned char *setup_packet,void *transfer_buffer,int buffer_length,usb_complete_t complete,void *context);
这个函数是用来正确初始化控制urb端点的。
还有一个初始化等时urb的,它现在还没有初始化函数,所以它们在被提交到USB核心前,必须在驱动程序中手工地进行初始化,可以参考内核源代码树下的/usr/src/~/drivers/usb/media下的konicawc.c文件。

F. linux虚拟机安装问题求助

是你的主机的硬盘满了,而不是 vb 的虚拟硬盘满了。
vb 的虚拟硬盘是变动大小的。
-------------------------------
FAT32 的话,你的虚拟机硬盘选择的是单文件方式,还是拆分文件?
FAT32 不支持大文件,这里必须选择拆分。不然你的虚拟机的硬盘选择再大也没用。

G. linux中怎么使用gdb调试进程有dettach

在2.5.60版Linux内核及以后,GDB对使用fork/vfork创建子进程的程序提供了follow-fork-mode选项来支持多进程调试。 follow-fork-mode的用法为: set follow-fork-mode [parentchild] parent: fork之后继续调试父进程,子进程不受影响。 child: fork之后调试子进程,父进程不受影响。 因此如果需要调试子进程,在启动gdb后: (gdb) set follow-fork-mode child并在子进程代码设置断点。 此外还有detach-on-fork参数,指示GDB在fork之后是否断开(detach)某个进程的调试,或者都交由GDB控制: set detach-on-fork [onoff] on: 断开调试follow-fork-mode指定的进程。 off: gdb将控制父进程和子进程。follow-fork-mode指定的进程将被调试,另一个进程置于暂停(suspended)状态。 注意,最好使用GDB 6.6或以上版本,如果你使用的是GDB6.4,就只有follow-fork-mode模式。 follow-fork-mode/detach-on-fork的使用还是比较简单的,但由于其系统内核/gdb版本限制,我们只能在符合要求的系统上才能使用。而且,由于follow-fork-mode的调试必然是从父进程开始的,对于fork多次,以至于出现孙进程或曾孙进程的系统,例如上图3进程系统,调试起来并不方便。 Attach子进程 众所周知,GDB有附着(attach)到正在运行的进程的功能,即attach <pid>命令。因此我们可以利用该命令attach到子进程然后进行调试。 例如我们要调试某个进程RIM_Oracle_Agent.9i,首先得到该进程的pid [root@tivf09 tianq]# ps -efgrep RIM_Oracle_Agent.9i nobody 6722 6721 0 05:57 ? 00:00:00 RIM_Oracle_Agent.9i root 7541 27816 0 06:10 pts/3 00:00:00 grep -i rim_oracle_agent.9i通过pstree可以看到,这是一个三进程系统,oserv是RIM_Oracle_prog的父进程,RIM_Oracle_prog又是RIM_Oracle_Agent.9i的父进程。 [root@tivf09 root]# pstree -H 6722通过 pstree 察看进程 启动GDB,attach到该进程 用 GDB 连接进程 现在就可以调试了。一个新的问题是,子进程一直在运行,attach上去后都不知道运行到哪里了。有没有办法解决呢? 一个办法是,在要调试的子进程初始代码中,比如main函数开始处,加入一段特殊代码,使子进程在某个条件成立时便循环睡眠等待,attach到进程后在该代码段后设上断点,再把成立的条件取消,使代码可以继续执行下去。 至于这段代码所采用的条件,看你的偏好了。比如我们可以检查一个指定的环境变量的值,或者检查一个特定的文件存不存在。以文件为例,其形式可以如下: void debug_wait(char *tag_file) { while(1) { if (tag_file存在) 睡眠一段时间; else break; } }当attach到进程后,在该段代码之后设上断点,再把该文件删除就OK了。当然你也可以采用其他的条件或形式,只要这个条件可以设置/检测即可。 Attach进程方法还是很方便的,它能够应付各种各样复杂的进程系统,比如孙子/曾孙进程,比如守护进程(daemon process),唯一需要的就是加入一小段代码。 GDB wrapper 很多时候,父进程 fork 出子进程,子进程会紧接着调用 exec族函数来执行新的代码。对于这种情况,我们也可以使用gdb wrapper 方法。它的优点是不用添加额外代码。 其基本原理是以gdb调用待执行代码作为一个新的整体来被exec函数执行,使得待执行代码始终处于gdb的控制中,这样我们自然能够调试该子进程代码。 还是上面那个例子,RIM_Oracle_prog fork出子进程后将紧接着执行RIM_Oracle_Agent.9i的二进制代码文件。我们将该文件重命名为RIM_Oracle_Agent.9i.binary,并新建一个名为RIM_Oracle_Agent.9i的shell脚本文件,其内容如下: [root@tivf09 bin]# mv RIM_Oracle_Agent.9i RIM_Oracle_Agent.9i.binary [root@tivf09 bin]# cat RIM_Oracle_Agent.9i #!/bin/sh gdb RIM_Oracle_Agent.binary当fork的子进程执行名为RIM_Oracle_Agent.9i的文件时,gdb会被首先启动,使得要调试的代码处于gdb控制之下。

H. 什么样的程序让linux负载变大

在linux系统里面,常见的有两个地方可以看到当前系统的最近平均负载,top命令和uptime,如果执行一下uptime命令的话,可以看到有一个load average,表示最近1分钟,5分钟,15分钟的系统负载。
# uptime
23:31:04 up 5 days, 10:20, 1 user, load average: 0.00, 0.01, 0.05
一般单核的CPU的话,负载到1证明系统已经运行比较满了,多核的话,有几个核就能到几。
但是,有没有仔细想过,这个负载值究竟可以有多高?
我们先用一个程序做下实验

等这个程序运行一会,再执行uptime看下负载
# uptime
23:44:53 up 5 days, 10:33, 2 users, load average: 16383.13, 14111.52, 7705.88
看到没,这个程序竟然把load神奇的刷到了16000这个级别,真是厉害,这个一下子似乎打破了对系统负载的认识。
原理是这样的,通过调用vfork产生指定数量的D状态的进程,从而提高负载。看看系统文档,是这样说的
vfork() differs from fork(2) in that the calling thread is suspended until the child terminates (either normally, by calling _exit(2), or abnormally, after delivery of a fatal signal), or it makes a call to execve(2). Untilthat point, the child shares all memory with its parent, including the stack.
vfork 的子进程只要不 execve 或者退出,父进程就一直挂着(在D状态)。这里就是让最后一个子进程用 scanf 等输入。
但是这个就是极限了吗?
程序员在这种事情上是不会停止追求的,下来再看一个终极版本的程序

执行一下
# stap -g loadavg.stp $(((1
看下效果
# uptime
23:48:19 up 5 days, 10:37, 2 users, load average: 9007199254740991.00, 14987.03, 9007199254740991.00
我天,这是要爆表了,终极load,系统要炸了吗?
不过,你知道其中的原理吗,vfork相当于还是利用了系统计算load的原理,通过增加D状态进程影响计算,这个终极版,则是直接修改计算过程中用到的参数,让系统算出一个极大值来,没有什么能够超越这个了。

阅读全文

与linuxsuspended相关的资料

热点内容
iphone6屏幕出现平行竖条纹 浏览:741
教育大数据应用典型示范项目 浏览:934
有什么好的消化内科科普网站 浏览:504
打开网络映射存储为什么特别慢 浏览:157
苹果手机摔弯了还能修吗 浏览:532
华中数控编程怎么换 浏览:874
word2007画图工具在哪里 浏览:565
广播式网络由什么组成 浏览:538
福州老用户升级4g校园套餐 浏览:644
jstr加点击事件 浏览:652
搜狗输入法最老版本下载地址 浏览:145
玛卡编程怎么样 浏览:302
怎么编程伺服器编码 浏览:109
什么是机密文件 浏览:258
网站收录量低应该如何解决 浏览:978
飞跃贷app官网 浏览:337
js正则表达式全为整数 浏览:561
在哪里免费下载大数据 浏览:218
linux怎么做视频网站 浏览:949
安卓舰娘登入不进去 浏览:145

友情链接