linux ioctl()详解

2023-11-15

 

一、ioctl的简介:

虽然在文件操作结构体"struct file_operations"中有很多对应的设备操作函数,但是有些命令是实在找不到对应的操作函数。如CD-ROM的驱动,想要一个弹出光驱的操作,这种操作并不是所有的字符设备都需要的,所以文件操作结构体也不会有对应的函数操作。


出于这样的原因,ioctl就有它的用处了————一些没办法归类的函数就统一放在ioctl这个函数操作中,通过指定的命令来实现对应的操作。所以,ioctl函数里面都实现了多个的对硬件的操作,通过应用层传入的命令来调用相应的操作。


来个图来说一下应用层与驱动函数的ioctl之间的联系:

上面的图可以看出,fd通过内核后找到对应的inodefile结构体指针并传给驱动函数,而另外两个参数却没有修改(类型改了没什么关系)


简单介绍一下函数:

int (*ioctl) (struct inode * node, struct file *filp, unsigned int cmd, unsigned long arg);

参数:

1)inodefileioctl的操作有可能是要修改文件的属性,或者访问硬件。要修改

文件属性的话,就要用到这两个结构体了,所以这里传来了它们的指针。

2)cmd:命令,接下来要长篇大论地说。

3)arg:参数,接下来也要长篇大论。

返回值:

1)如果传入的非法命令,ioctl返回错误号-EINVAL

2)内核中的驱动函数返回值都有一个默认的方法,只要是正数,内核就会傻乎乎的认为这是正确的返回,并把它传给应用层,如果是负值,内核就会认为它是错误号了。

Ioctl里面多个不同的命令,那就要看它函数的实现来决定返回值了。打个比方,如果ioctl里面有一个类似read的函数,那返回值也就可以像read一样返回。

当然,不返回也是可以的。


二、ioctlcmd


说白了,cmd就是一个数,如果应用层传来的数值在驱动中有对应的操作,这样就就可以了。


来个最简单的ioctl实现:3rd_char_4/1st


1)要先定义个命令,就用一个简单的0,来个命令的头文件,驱动和应用函数都要包含这个头文件

/*test_cmd.h*/

1 #ifndef _TEST_CMD_H

2 #define _TEST_CMD_H

3

4 #define TEST_CLEAR 0

5

6 #endif /*_TEST_CMD_H*/

2)驱动实现ioctl

命令TEST_CLEAR的操作就是清空驱动中的kbuf

122 int test_ioctl (struct inode *node, struct file *filp, unsigned int cmd, uns igned long arg)

123 {

124 int ret = 0;

125 struct _test_t *dev = filp->private_data;

126

127 switch(cmd){

128 case TEST_CLEAR:

129 memset(dev->kbuf, 0, DEV_SIZE);

130 dev->cur_size = 0;

131 filp->f_pos = 0;

132 ret = 0;

133 break;

134 default: /*命令错误时的处理*/

135 P_DEBUG("error cmd!\n");

136 ret = - EINVAL;

137 break;

138 }

139

140 return ret;

141 }


3)再来个应用程序:

1 #include <stdio.h>

2 #include <sys/types.h>

3 #include <sys/stat.h>

4 #include <fcntl.h>

5 #include <sys/ioctl.h>

6 #include "test_cmd.h"

7

8 int main(void)

9 {

10 char buf[20];

11 int fd;

12 int ret;

13

14 fd = open("/dev/test", O_RDWR);

15 if(fd < 0)

16 {

17 perror("open");

18 return -1;

19 }

20

21 write(fd, "xiao bai", 10); //1先写入

22

23 ioctl(fd, TEST_CLEAR); //2再清空

24

25 ret = read(fd, buf, 10); //3再验证

26 if(ret < 0)

27 {

28 perror("read");

29 }

30

31 close(fd);

32 return 0;

33 }

注:这里为了read返回出错,我修改了驱动的readwrite函数的开始时的第一个

判断,一看就知道了。


4)验证一下:

[root: 1st]# insmod test.ko

major[253] minor[0]

hello kernel

[root: 1st]# mknod /dev/test c 253 0

[root: 1st]# ./app

<kernel>[test_write]write 10 bytes, cur_size:[10]

<kernel>[test_write]kbuf is [xiao bai]

read: No such device or address //哈哈!出错了!因为没数据读取。



按照上面的方法来定义一个命令是完全可以的,但内核开发人员发现这样有点不对劲。

如果有两个不同的设备,但它们的ioctlcmd却一样的,哪天有谁不小心打开错了,并且调用ioctl,这样就完蛋了。因为这个文件里面同样有cmd对应实现。

为了防止这样的事情发生,内核对cmd又有了新的定义,规定了cmd都应该不一样。


三、ioctl中的cmd


一个cmd被分为了4个段,每一段都有各自的意义,cmd的定义在<linux/ioctl.h>。注:但实际上<linux/ioctl.h>中只是包含了<asm/ioctl.h>,这说明了这是跟平台相关的,ARM的定义在<arch/arm/include/asm/ioctl.h>,但这文件也是包含别的文件<asm-generic/ioctl.h>,千找万找,终于找到了。


<asm-generic/ioctl.h>中,cmd拆分如下:

解释一下四部分,全部都在<asm-generic/ioctl.h>ioctl-number.txt这两个文档有说明。

1)幻数:说得再好听的名字也只不过是个0~0xff的数,占8bit(_IOC_TYPEBITS)。这个数是用来区分不同的驱动的,像设备号申请的时候一样,内核有一个文档给出一些推荐的或者已经被使用的幻数。

/*Documentation/ioctl/ioctl-number.txt*/

164 'w' all CERN SCI driver

165 'y' 00-1F packet based user level communications

166 <mailto:zapman@interlan.net>

167 'z' 00-3F CAN bus card

168 <mailto:hdstich@connectu.ulm.circular.de>

169 'z' 40-7F CAN bus card

170 <mailto:oe@port.de>

可以看到'x'是还没有人用的,我就拿这个当幻数!


2)序数:用这个数来给自己的命令编号,占8bit(_IOC_NRBITS),我的程序从1开始排序。


3)数据传输方向:占2bit(_IOC_DIRBITS)。如果涉及到要传参,内核要求描述一下传输的方向,传输的方向是以应用层的角度来描述的。

1)_IOC_NONE:值为0,无数据传输。

2)_IOC_READ:值为1,从设备驱动读取数据。

3)_IOC_WRITE:值为2,往设备驱动写入数据。

4)_IOC_READ|_IOC_WRITE:双向数据传输。


4)数据大小:与体系结构相关ARM下占14bit(_IOC_SIZEBITS),如果数据是int,内核给这个赋的值就是sizeof(int)


强调一下,内核是要求按这样的方法把cmd分类,当然你也可以不这样干,这只是为了迎合内核的要求,让自己的程序看上去很正宗。上面我的程序没按要求照样运行。


既然内核这样定义cmd,就肯定有方法让用户方便定义:

_IO(type,nr) //没有参数的命令

_IOR(type,nr,size) //该命令是从驱动读取数据

_IOW(type,nr,size) //该命令是从驱动写入数据

_IOWR(type,nr,size) //双向数据传输

上面的命令已经定义了方向,我们要传的是幻数(type)、序号(nr)和大小(size)。在这里szie的参数只需要填参数的类型,如int,上面的命令就会帮你检测类型的正确然后赋值sizeof(int)


有生成cmd的命令就必有拆分cmd的命令:

_IOC_DIR(cmd) //从命令中提取方向

_IOC_TYPE(cmd) //从命令中提取幻数

_IOC_NR(cmd) //从命令中提取序数

_IOC_SIZE(cmd) //从命令中提取数据大小


越讲就越复杂了,既然讲到这,随便就讲一下预定义命令。

预定义命令是由内核来识别并且实现相应的操作,换句话说,一旦你使用了这些命令,你压根也不要指望你的驱动程序能够收到,因为内核拿掉就把它处理掉了。


分为三类:

1)可用于任何文件的命令

2)只用于普通文件的命令

3)特定文件系统类型的命令


其实上面的我三类我也没搞懂,反正我自己随便编了几个数当命令都没出错,如果真的怕出错,那就不要用别人已经使用的幻数就行了。


讲了这么多,终于要上程序了,修改一下上一个程序,让它看起来比较有内涵。

/3rd_char/3rd_char_4/2nd

1)先改一下命令:

/*test_cmd.h*/

1 #ifndef _TEST_CMD_H

2 #define _TEST_CMD_H

3

4 #define TEST_MAGIC 'x' //定义幻数

5 #define TEST_MAX_NR 1 //定义命令的最大序数,只有一个命令当然是1

6

7 #define TEST_CLEAR _IO(TEST_MAGIC, 0)

8

9 #endif /*_TEST_CMD_H*/


2)既然这么辛苦改了cmd,在驱动函数当然要做一些参数检验:

/*test.c*/

122 int test_ioctl (struct inode *node, struct file *filp, unsigned int cmd, unsigned long arg)

123 {

124 int ret = 0;

125 struct _test_t *dev = filp->private_data;

126

127 /*既然这么费劲定义了命令,当然要检验命令是否有效*/

128 if(_IOC_TYPE(cmd) != TEST_MAGIC) return - EINVAL;

129 if(_IOC_NR(cmd) > TEST_MAX_NR) return - EINVAL;

130

131 switch(cmd){

132 case TEST_CLEAR:

133 memset(dev->kbuf, 0, DEV_SIZE);

134 dev->cur_size = 0;

135 filp->f_pos = 0;

136 ret = 0;

137 break;

138 default: /*命令错误时的处理*/

139 P_DEBUG("error cmd!\n");

140 ret = - EINVAL;

141 break;

142 }

143

144 return ret;

145 }

每个参数的传入都会先检验一下幻数还有序数是否正确。


3)应用程序的验证

结果跟上一个完全一样,因为命令的操作没有修改

[root: 2nd]# insmod test.ko

major[253] minor[0]

hello kernel

[root: 2nd]# mknod /dev/test c 253 0

[root: 2nd]# ./app

<kernel>[test_write]write 10 bytes, cur_size:[10]

<kernel>[test_write]kbuf is [xiao bai]

read: No such device or address


五、ioctl中的arg之整数传参。



上面讲的例子都没有使用ioctl的传参。这里先要说一下ioctl传参的方式。


应用层的ioctl的第三个参数是"...",这个跟printf"..."可不一样,printf中是意味这你可以传任意个数的参数,而ioctl最多也只能传一个,"..."的意思是让内核不要检查这个参数的类型。也就是说,从用户层可以传入任何参数,只要你传入的个数是1.


一般会有两种的传参方法:

1)整数,那可是省力又省心,直接使用就可以了。

2)指针,通过指针的就传什么类型都可以了,当然用起来就比较烦。


先说简单的,使用整数作为参数:

例子,实现个命令,通过传入参数更改偏移量,虽然llseek已经实现,这里只是想验证一下正数传参的方法。


1)先加个命令:

1 #ifndef _TEST_CMD_H

2 #define _TEST_CMD_H

3

4 #define TEST_MAGIC 'x' //定义幻数

5 #define TEST_MAX_NR 2 //定义命令的最大序数

6

7 #define TEST_CLEAR _IO(TEST_MAGIC, 1)

8 #define TEST_OFFSET _IO(TEST_MAGIC, 2)

9

10 #endif /*_TEST_CMD_H*/

这里有人会问了,明明你是要传入参数,为什么不用_IOW而用_IO定义命令呢?

原因有二:

1)因为定义数据的传输方向是为了好让驱动的函数验证数据的安全性,而一般指针才需要检验安全性,因为有人会恶意传参(回想一下copy_to_user)

2)个人喜好,方便我写程序介绍另一种传参方法,说白了命令也只是一个数,只要不要跟预定义命令冲突就可以了。


2)更新test_ioctl

122 int test_ioctl (struct inode *node, struct file *filp, unsigned int cmd, uns igned long arg)

123 {

124 int ret = 0;

125 struct _test_t *dev = filp->private_data;

126

127 /*既然这么费劲定义了命令,当然要检验命令是否有效*/

128 if(_IOC_TYPE(cmd) != TEST_MAGIC) return - EINVAL;

129 if(_IOC_NR(cmd) > TEST_MAX_NR) return - EINVAL;

130

131 switch(cmd){

132 case TEST_CLEAR:

133 memset(dev->kbuf, 0, DEV_SIZE);

134 dev->cur_size = 0;

135 filp->f_pos = 0;

136 ret = 0;

137 break;

138 case TEST_OFFSET: //根据传入的参数更改偏移量

139 filp->f_pos += (int)arg;

140 P_DEBUG("change offset!\n");

141 ret = 0;

142 break;

143 default: /*命令错误时的处理*/

144 P_DEBUG("error cmd!\n");

145 ret = - EINVAL;

146 break;

147 }

148

149 return ret;

150 }

TSET_OFFSET命令就是根据传参更改偏移量,不过这里要注意一个问题,那就是参数的类型,驱动函数必须要知道从应用传来的参数是什么类型,不然就没法使用。在这个函数里,从应用层传来的参数是int,因此在驱动中也得用int


3)再改一下应用程序:

1 #include <stdio.h>

2 #include <sys/types.h>

3 #include <sys/stat.h>

4 #include <fcntl.h>

5 #include <sys/ioctl.h>

6

7 #include "test_cmd.h"

8

9 int main(void)

10 {

11 char buf[20];

12 int fd;

13 int ret;

14

15 fd = open("/dev/test", O_RDWR);

16 if(fd < 0)

17 {

18 perror("open");

19 return -1;

20 }

21

22 write(fd, "xiao bai", 10); //先写入

23

24 ioctl(fd, TEST_OFFSET, -10); //再改偏移量

25

26 ret = read(fd, buf, 10); //再读数据

27 printf("<app> buf is [%s]\n", buf);

28 if(ret < 0)

29 {

30 perror("read");

31 }

32

33 close(fd);

34 return 0;

35 }


4)验证一下

[root: 3rd]# insmod test.ko

major[253] minor[0]

hello kernel

[root: 3rd]# mknod /dev/test c 253 0

[root: 3rd]# ./app

<kernel>[test_write]write 10 bytes, cur_size:[10]

<kernel>[test_write]kbuf is [xiao bai]

<kernel>[test_ioctl]change offset! //更改偏移量

<kernel>[test_read]read 10 bytes, cur_size:[0] //没错误,成功读取!

<app> buf is [xiao bai]


上面的传参很简单把,接下来说一下以指针传参。

考虑到参数不可能永远只是一个正数这么简单,如果要传多一点的东西,譬如是结构体,那就得用上指针了。


六、ioctl中的arg之指针传参。


一讲到从应用程序传来的指针,就得想起我邪恶的传入了非法指针的例子。所以,驱动程序中任何与应用层打交道的指针,都得先检验指针的安全性。


说到这检验又有两种方法:

1)用的时候才检验。

2)一进来ioctl就检验。


先说用的时候检验,说白了就是用copy_xx_user系列函数,下面实现一下:

1)先定义个命令

1 #ifndef _TEST_CMD_H

2 #define _TEST_CMD_H

3

4 struct ioctl_data{

5 unsigned int size;

6 char buf[100];

7 };

8

9 #define DEV_SIZE 100

10

11 #define TEST_MAGIC 'x' //定义幻数

12 #define TEST_MAX_NR 3 //定义命令的最大序数

13

14 #define TEST_CLEAR _IO(TEST_MAGIC, 1)

15 #define TEST_OFFSET _IO(TEST_MAGIC, 2)

16 #define TEST_KBUF _IO(TEST_MAGIC, 3)

17

18 #endif /*_TEST_CMD_H*/

这里有定义多了一个函数,虽然这个命令是涉及到了指针的传参,但我还是_IOW,还是那一句,现在还不需要用上。

该命令的操作是传进一个结构体指针,驱动根据结构体的内容修改kbufcur_size和偏移量。


2)来个实现函数:

122 int test_ioctl (struct inode *node, struct file *filp, unsigned int cmd, uns igned long arg)

123 {

124 int ret = 0;

125 struct _test_t *dev = filp->private_data;

126 struct ioctl_data val;

127

128 /*既然这么费劲定义了命令,当然要检验命令是否有效*/

129 if(_IOC_TYPE(cmd) != TEST_MAGIC) return - EINVAL;

130 if(_IOC_NR(cmd) > TEST_MAX_NR) return - EINVAL;

131

132 switch(cmd){

133 case TEST_CLEAR:

134 memset(dev->kbuf, 0, DEV_SIZE);

135 dev->cur_size = 0;

136 filp->f_pos = 0;

137 ret = 0;

138 break;

139 case TEST_OFFSET: //根据传入的参数更改偏移量

140 filp->f_pos += (int)arg;

141 P_DEBUG("change offset!\n");

142 ret = 0;

143 break;

144 case TEST_KBUF: //修改kbuf

145 if(copy_from_user(&val, (struct ioctl_data *)arg, sizeof(struct ioctl_data))){

146 ret = - EFAULT;

147 goto RET;

148 }

149 memset(dev->kbuf, 0, DEV_SIZE);

150 memcpy(dev->kbuf, val.buf, val.size);

151 dev->cur_size = val.size;

152 filp->f_pos = 0;

153 ret = 0;

154 break;

155 default: /*命令错误时的处理*/

156 P_DEBUG("error cmd!\n");

157 ret = - EINVAL;

158 break;

159 }

160

161 RET:

162 return ret;

163 }

145行,因为指针是从用户程序传来,所以必须检查安全性。


3)来个应用程序

9 int main(void)

10 {

11 char buf[20];

12 int fd;

13 int ret;

14

15 struct ioctl_data my_data= {

16 .size = 10,

17 .buf = "123456789"

18 };

19

20 fd = open("/dev/test", O_RDWR);

21 if(fd < 0)

22 {

23 perror("open");

24 return -1;

25 }

26

27 write(fd, "xiao bai", 10);

28

29 ioctl(fd, TEST_KBUF, &my_data);

30

31 ret = read(fd, buf, 10);

32 printf("<app> buf is [%s]\n", buf);

33 if(ret < 0)

34 {

35 perror("read");

36 }

37

38 close(fd);

39 return 0;

40 }


4)再来验证一下:

[root: 4th]# ./app

<kernel>[test_write]write 10 bytes, cur_size:[10]

<kernel>[test_write]kbuf is [xiao bai]

<kernel>[test_read]read 10 bytes, cur_size:[0]

<app> buf is [123456789] //成功!

注:类似copy_xx_user的函数含有put_userget_user等,我就不细说了。

下面说第二种方法:进入ioctl后使用access_ok检测。

声明一下:下面的验证方法是不正确的。如果不想看下去的话,今天的内容已经讲完了。


先说一下access_ok的使用

access_ok(type, addr, size)

使用:检测地址的安全性

参数:

type:用于指定数据传输的方向,VERIFY_READ表示要读取应用层数据,VERIFT_WRITE表示要往应用层写如数据。注意:这里和IOR IOW的方向相反。如果既读取又写入,那就使用VERIFY_WRITE

addr:用户空间的地址

size:数据的大小

返回值:

成功返回1,失败返回0


既然知道怎么用,就直接来程序了:

1)定义命令

1 #ifndef _TEST_CMD_H

2 #define _TEST_CMD_H

3

4 struct ioctl_data{

5 unsigned int size;

6 char buf[100];

7 };

8

9 #define DEV_SIZE 100

10

11 #define TEST_MAGIC 'x' //定义幻数

12 #define TEST_MAX_NR 3 //定义命令的最大序数

13

14 #define TEST_CLEAR _IO(TEST_MAGIC, 1)

15 #define TEST_OFFSET _IO(TEST_MAGIC, 2)

16 #define TEST_KBUF _IOW(TEST_MAGIC, 3, struct ioctl_data)

17

18 #endif /*_TEST_CMD_H*/

这里终于要用_IOW了!


2)实现ioctl

122 int test_ioctl (struct inode *node, struct file *filp, unsigned int cmd, uns igned long arg)

123 {

124 int ret = 0;

125 struct _test_t *dev = filp->private_data;

126

127 /*既然这么费劲定义了命令,当然要检验命令是否有效*/

128 if(_IOC_TYPE(cmd) != TEST_MAGIC) return - EINVAL;

129 if(_IOC_NR(cmd) > TEST_MAX_NR) return - EINVAL;

130 /*根据提取命令指定的方向判断指针的安全性*/

131 if(_IOC_DIR(cmd) & _IOC_READ)

132 ret = access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd));

133 else if(_IOC_DIR(cmd) & _IOC_WRITE)

134 ret = access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd));

135 if(!ret) return - EFAULT;

136

137 switch(cmd){

138 case TEST_CLEAR:

139 memset(dev->kbuf, 0, DEV_SIZE);

140 dev->cur_size = 0;

141 filp->f_pos = 0;

142 ret = 0;

143 break;

144 case TEST_OFFSET: //根据传入的参数更改偏移量

145 filp->f_pos += (int)arg;

146 P_DEBUG("change offset!\n");

147 ret = 0;

148 break;

149 case TEST_KBUF: //修改kbuf

150 memset(dev->kbuf, 0, DEV_SIZE);

151 memcpy(dev->kbuf, ((struct ioctl_data *)arg)->buf,

152 ((struct ioctl_data *)arg)->size);

153 dev->cur_size = ((struct ioctl_data *)arg)->size;

154 filp->f_pos = 0;

155 ret = 0;

156 break;

157 default: /*命令错误时的处理*/

158 P_DEBUG("error cmd!\n");

159 ret = - EINVAL;

160 break;

161 }

162

163 return ret;

164 }

上面并没有用copy_to_user,而是通过access_ok来检测。


3)再来个应用程序:

9 int main(void)

10 {

11 char buf[20];

12 int fd;

13 int ret;

14

15 struct ioctl_data my_data= {

16 .size = 10,

17 .buf = "123456789"

18 };

19

20 fd = open("/dev/test", O_RDWR);

21 if(fd < 0)

22 {

23 perror("open");

24 return -1;

25 }

26

27 write(fd, "xiao bai", 10);

28

29 ret = ioctl(fd, TEST_KBUF, &my_data);

30 if(ret < 0)

31 {

32 perror("ioctl");

33 }

34

35 ret = read(fd, buf, 10);

36 printf("<app> buf is [%s]\n", buf);

37 if(ret < 0)

38 {

39 perror("read");

40 }

41

42 close(fd);

43 return 0;

44 }


4)验证一下:效果和上一个一样

[root: 5th]# ./app

<kernel>[test_write]write 10 bytes, cur_size:[10]

<kernel>[test_write]kbuf is [xiao bai]

<kernel>[test_read]read 10 bytes, cur_size:[0]

<app> buf is [123456789]


下面就要如正题了,这个驱动是有问题的,那就是验证安全性完全不起作用!当我传入非法指针时,驱动同样会输出,不信可以自己传个邪恶地址(void *)0进去试一下。


修改应用程序一样代码:

29 ret = ioctl(fd, TEST_KBUF, &my_data);


上面是我做的错误实现,我本来想验证,只要经过access_ok检验,数据就会安全,没想到经过access_ok检验之后照样会出错。

但是,copy_to_user同样是先调用access_ok再调用memcpy,它却没出错。这个我事情我现在都没搞明白,如果谁知道了麻烦指点一下。


我查了设备驱动第三版,在144页有这样的说法:

1.access_ok并没有做完的所有的内存检查,

2.大多数的驱动代码都不是用access_ok的,后面的内存管理会讲述。


在这里书本上有这样的约定:(都是我自己的理解)

1.传入指针需要检查安全性。memcpy函数尽量不要在内核中使用。

2.copy_to_user.copy_from_user.get_user.put_user函数会再拷贝数据前检测指针的安全性。不需要access_ok

3.如果在ioctl函数开头使用了accsee_ok检验数据,接下来的代码可以使用__put_user__get_user这些不需要检测的函数(书上有例子)


虽然还有写东西还没搞懂,但个人觉得,如果使用个access_ok要这么麻烦的话,那我就不用好了,以后我就使用copy_xx_user函数,省力又省心。




七、总结:


这次讲了ioctl的实现:

1)命令是怎么定义。

2)参数怎么传递


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

linux ioctl()详解 的相关文章

  • 如何将后台作业的输出分配给 bash 变量?

    我想在 bash 中运行后台作业并将其结果分配给一个变量 我不喜欢使用临时文件 并且希望同时运行多个类似的后台任务 root root var echo hello world root root echo var hello world
  • 配置:错误:无法运行C编译的程序

    我正在尝试使用 Debian Wheezy 操作系统在我的 Raspberry Pi 上安装不同的软件 当我运行尝试配置软件时 我尝试安装我得到此输出 checking for C compiler default output file
  • pprof 和 ps 之间的内存使用差异

    我一直在尝试分析用 cobra 构建的 cli 工具的堆使用情况 这pprof工具显示如下 Flat Flat Sum Cum Cum Name Inlined 1 58GB 49 98 49 98 1 58GB 49 98 os Read
  • 推荐用于小型站点的 IRC 服务器 (ircd)? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 情况 我想使用 IRC 机器人作为我正在研究的其他代码的通用通信接口 服务器硬件陈旧且内存不足 但运行在相对最新的 Debian GNU
  • 码头无故停止

    我需要经验丰富的码头用户的建议 我在负载均衡器 亚马逊云 后面维护着 2 台 Linux 机器 使用 Jetty 9 0 3 有时我的 Jetty 容器会被 Thread 2 无故关闭 同时地 显示以下日志并且容器无故停止 没有错误 没有例
  • 从 Python 访问 802.11 无线管理帧

    我想从 Linux 上的 Python 嗅探 802 11 管理 探测请求 帧 这可以从 Scapy 中实现 如下所示 coding utf 8 from scapy all import def proc p if p haslayer
  • 如何确定代码是否在信号处理程序上下文中运行?

    我刚刚发现有人正在从信号处理程序调用我编写的绝对不是异步信号安全的函数 所以 现在我很好奇 如何避免这种情况再次发生 我希望能够轻松确定我的代码是否在信号处理程序上下文中运行 语言是 C 但该解决方案不适用于任何语言吗 int myfunc
  • 如何设置Java线程的CPU核心亲和力?

    我搜索了以前关于类似主题的帖子 但找不到合适的答案 因此提出这个问题 非常感谢您帮助回答 我知道在 Linux 中通过任务集命令设置进程与特定 CPU 核心的关联性 但我想设置 Java 线程与特定 cpu 核心的亲和力 以便属于同一进程的
  • 无需 root 访问权限即可安装 zsh? [关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 有可能 以及如何 我确实需要在几台具有 ssh 访问权限 但没有 root 访问权限 的远程计算机上使用此功能 下载 zsh wget O zsh t
  • 运行此处编译的 C 程序会导致在另一台服务器上找不到 GLIBC 库错误 - 是我的错还是他们的错?

    此处编译的 C 程序在我们的 Ubuntu 服务器上运行良好 但是当其他人尝试在他们的特定 Linux 服务器上运行它时 他们会收到以下错误 myprog install lib tls libc so 6 version GLIBC 2
  • 用于读取文件的 Bash 脚本

    不知道为什么最后一行没有从脚本中删除 bin bash FILENAME 1 while read line do cut d f2 echo line done lt FILENAME cat file 1 test 2 test 3 t
  • ubuntu 的 CSS 更少(并且自动编译)? [关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 我尝试过 simples 但现在 l
  • 使用c在linux上分块读写

    我有一个 ASCII 文件 其中每一行都包含一个可变长度的记录 例如 Record 1 15 characters Record 2 200 characters Record 3 500 characters Record n X cha
  • 裸机交叉编译器输入

    裸机交叉编译器的输入限制是什么 比如它不编译带有指针或 malloc 的程序 或者任何需要比底层硬件更多的东西 以及如何才能找到这些限制 我还想问 我为目标 mips 构建了一个交叉编译器 我需要使用这个交叉编译器创建一个 mips 可执行
  • 如何反汇编、修改然后重新组装 Linux 可执行文件?

    无论如何 这可以做到吗 我使用过 objdump 但它不会产生我所知道的任何汇编器都可以接受的汇编输出 我希望能够更改可执行文件中的指令 然后对其进行测试 我认为没有任何可靠的方法可以做到这一点 机器代码格式非常复杂 比汇编文件还要复杂 实
  • 可以作为命令行参数传递多少数据?

    在 Linux 下生成进程时可以发送多少字节作为命令行参数 gahooa 推荐了一篇好文章http www in ulm de mascheck various argmax http www in ulm de mascheck vari
  • 如何列出 nginx 中的所有虚拟主机

    有没有一个命令可以列出 CentOS 上 nginx 下运行的所有虚拟主机或服务器 我想将结果通过管道传输到文本文件以用于报告目的 我正在寻找与我用于 Apache 的命令类似的命令 apachectl S 2 gt 1 grep 端口 8
  • 如何在perl中使用O_ASYNC和fcntl?

    我想使用 O ASYNC 选项 当管道可以读取时 SIGIO 的处理程序将运行 但以下代码不起作用 任何人都可以帮助我吗 bin env perl use Fcntl SIG IO sub print catch SIGIO n my fl
  • 在非实时操作系统/内核上执行接近实时任务的最佳方法是什么?

    在一台 GNU Linux 机器上 如果想要执行 实时 亚毫秒级时间关键 任务 您几乎总是必须经历漫长 复杂且容易出现问题的内核补丁过程 以提供足够的支持 1 http en wikipedia org wiki RTLinux Backg
  • 了解 Linux oom-killer 日志

    我的应用程序被 oom killer 杀死了 它是在实时 USB 上运行的 Ubuntu 11 10 无需交换 PC 具有 1 Gig 的 RAM 唯一运行的应用程序 除了所有内置的 Ubuntu 东西 是我的程序 flasherav 请注

随机推荐

  • 【无功优化】基于教与学算法实现IEEE_33节点无功优化附matlab代码

    作者简介 热爱科研的Matlab仿真开发者 修心和技术同步精进 matlab项目合作可私信 个人主页 Matlab科研工作室 个人信条 格物致知 更多Matlab仿真内容点击 智能优化算法 神经网络预测 雷达通信 无线传感器 电力系统 信号
  • Linux一行命令筛选并停止某个服务的进程

    Linux下 筛选某个服务 如nginx 的进程命令 ps ef grep nginx 如果想停掉相应的进程则可以使用kill命令 如果想一行命令筛选出进程号 并kill掉 则 ps ef grep nginx grep v grep aw
  • 解决VC6在Win7或Win10下调试无法结束进程的Bug

    自己的系统是Win7 装上了VC6 调试一段小代码之后再次编译的时候就提示如下的错误 LINK fatal error LNK1168 cannot open Debug 1 exe for writing 意思就是编译要生成同名的 1 e
  • vue中使用Swiper

    一 安装依赖 npm i swiper 二 项目中使用 import swiper swiperSlide from vue awesome swiper import swiper css swiper css div class lb
  • JavaScript基础Day03:数组和函数

    JavaScript基础Day03 文章目录 JavaScript基础Day03 一 关键字break和continue 二 数组 1 数组的定义 2 数组的概念 3 创建数组 4 遍历数组 5 重点 冒泡排序 三 函数 1 参数 2 返回
  • C++与 python 变量生存周期比较

    1 C 中变量生存周期 参考 https blog csdn net darkxiaoming article details 70232620 在C 中变量有以下两种生存周期 变量由编译程序在编译时给其分配存储空间 称为静态存储分配 并在
  • 错误 D8016 “/O2”和“/RTC1”命令行选项不兼容

    错误方式 Debug模式下 优化 最大优化 基本运行时检查 两者RTC1 正确 最大优化 默认值 优化 最大优化 O2 基本运行时检查 设置 默认值
  • LInux下几种定时器的比较和使用

    在数据通信过程中 会遇到对数据发送时间的格式要求 所以要在应用中根据实际要求选择不同的定时器 就要考虑到几种应用定时器的特点 定时器文章参考 一般而言有 1 sleep usleep和nanosleep sleep 和nanosleep 都
  • C语言:利用函数递归实现计算n!。

    C语言 利用函数递归实现计算n include
  • 简单javascript的使用

    1 javascript的简介 是基于对象和事件驱动的语言 应用于客户端 基于对象 提供了好多对象 可以直接拿过来使用 事件驱动 html做网站静态效果 javascript动态效果 客户端 专门指浏览器 js的特点 1 交互性 信息的动态
  • 【Python文件的使用】

    文章目录 一 文件概述 1 文件类别 2 文件路径 3 文件的编码方式 二 文件操作 1 文件打开 2 文件读写 3 文件关闭 三 操作实例 一 文件概述 1 文件类别 文件是一个存储在辅助存储器上的数据序列 可以包含任何数据内容 概念上
  • 蓝桥杯.Java.数列排序

    问题描述 给定一个长度为n的数列 将这个数列按从小到大的顺序排列 1 lt n lt 200 输入格式 1 第一行为一个整数n 2 第二行包含n个整数 为待排序的数 每个整数的绝对值小于10000 输出格式 输出一行 按从小到大的顺序输出排
  • android 实现自动输入文本效果

    此控件的功能是帮助用户实现自动输入 例如当用户输入一个字符后 能够根据这个字符提示显示出与之相关的数据 里面用到了一个适配器来实现此功能 源代码如下 package com example autosearch import android
  • 土地调查图斑编号_土地年度变更调查“图斑类型”说明

    年 度 土 地 变 更 调 查 图 斑 类 型 年度土地变更调查 图斑类型 共分为11大类27个二级类 根据影像和数据库情况 分别填写相应数字代码 大类填写阿拉伯数字 小类填写大写的英文字母 如 1A 第1类 前时相影像有植被覆盖或明显非建
  • Java 多线程 --- 锁的概念和类型划分

    Java 多线程 锁的概念和类型划分 锁的概念 锁可以保证 原子性 可见性 有序性 乐观锁与悲观锁 公平锁与非公平锁 什么是可重入锁 独占锁与共享锁 轻量级锁和重量级锁 自旋锁 Spinlock 锁泄露 锁的概念 锁可以将多个线程对共享数据
  • 数据中心的拥塞控制(1)CN

    一 概述 CN来自于IEEE802 1Qau 它的目地是为带宽 时延积的量级为5Mbit或更小值的网络域中的长时间存在的流增加拥塞管理功能 这种流常存在于DCB网络 存储网络 计算机集群网络等环境中 因而DCB也常用在这些网络环境中 为了使
  • vue父子组件&继承组件的生命周期以及应用

    父子组件的生命周期顺序 今天在做项目时候 发现了一个问题 那就是父子组件的执行顺序问题 在我印象里 肯定是先执行父组件的生命周期 再执行子组件的生命周期 但其实并不是这样的 我们来看代码 我们先用vue cli搭建一个项目 用什么搭建并不重
  • python爬虫实战---爬取大众点评评论

    python爬虫实战 爬取大众点评评论 加密字体 1 首先打开一个店铺找到评论 很多人学习python 不知道从何学起 很多人学习python 掌握了基本语法过后 不知道在哪里寻找案例上手 很多已经做案例的人 却不知道如何去学习更加高深的知
  • [git]使用git+gitee实现在两台电脑数据同步

    如果是使用Mac电脑安装git后右键看不到git bash here 直接右击打开终端即可 不影响 目录 一 准备工作 1 获取两台电脑的SSH公钥 添加到gitee 2 在gitee创建仓库 二 从电脑一 想要共享的文件夹所在的电脑 上传
  • linux ioctl()详解

    一 ioctl的简介 虽然在文件操作结构体 struct file operations 中有很多对应的设备操作函数 但是有些命令是实在找不到对应的操作函数 如CD ROM的驱动 想要一个弹出光驱的操作 这种操作并不是所有的字符设备都需要的