------------------------------------------------------------
author: hjjdebug
date: 2024年 07月 14日 星期日 10:39:52 CST
description: errno 是个啥?
------------------------------------------------------------
linux 中, errno 定义在<errno.h>中, 原文如下:
/* The error code set by various library functions. */
extern int *__errno_location (void) __THROW __attribute_const__;
# define errno (*__errno_location ())
可见:
1. errno 是一个宏
#define errno blablabla....
2. errno 是一个函数调用返回的整数值.
# define errno (*__errno_location ())
函数调用返回的是一个整形数地址. 解引用得到数值
3. __errno_location() 是个啥?
这是个库函数, 我这里不准备详细研究这个函数, 但也要大致研究一下这个库函数的返回值, errno.
4. errno 是一个全局变量吗?不是,它是线程变量.
全局变量是属于进程的,而errno 是属于线程.
进程变量在多线程环境下有安全性问题. 即你刚刚写给它一个值, 再读回来可能就不是你写的那个值了.
而线程变量, 其它线程是不会干扰到你的线程运行的.
下面我们给出 errno 是线程变量的测试程序.
说明errno 是一个线程安全变量, 每一个线程都有一个自己的errno 变量与之对应.
$ cat main.cpp
#include <stdio.h> // for printf
#include <errno.h> // for errno
#include <pthread.h> // for pthread_create
#include <unistd.h> // for syscall
#include <sys/syscall.h> // for __NR_gettid
#define NTHREADS 3
#define gettid() syscall(__NR_gettid)
void *thread_function(void *pData)
{
int d=*(int *)pData;
printf("thread_id:%ld,thread_self:%lx, addr(pData):%p,addr(d):%p,addr(errno):%p\n",gettid(), pthread_self(),pData,&d,&errno);
return NULL;
}
int main()
{
pthread_t thread_id[NTHREADS];
int i, j;
for(i=0; i < NTHREADS; i++)
{
pthread_create( &thread_id[i], NULL, thread_function, &i );
}
for(j=0; j < NTHREADS; j++)
{
pthread_join( thread_id[j], NULL);
}
return 0;
}
// $ ./errno
// thread_id:4486,thread_self:7f9b37bf1700, addr(pData):0x7ffff95eee5c,addr(d):0x7f9b37bf0ed4,addr(errno):0x7f9b37bf1680
// thread_id:4487,thread_self:7f9b37260700, addr(pData):0x7ffff95eee5c,addr(d):0x7f9b3725fed4,addr(errno):0x7f9b37260680
// thread_id:4488,thread_self:7f9b368cf700, addr(pData):0x7ffff95eee5c,addr(d):0x7f9b368ceed4,addr(errno):0x7f9b368cf680
// 可见pData 是传来的变量i的地址,是进程变量
// d 是线程变量地址,errno也是线程变量地址,不同的线程,访问的是不同的地址,虽然它们的名字都叫d, errno
// thread_id 是系统分配的线程号, thread_self是线程的地址边界
5. 怎样得到errno 对应的错误信息?
可以用 strerror(errno) 函数, 该函数在 string.h 头文件中记录.
下面给出一个简单的errno 信息打印程序, 及运行结果
$ cat main.cpp
#include <stdio.h>
#include <errno.h>
#include <string.h>
int main(void)
{
for(int i=0;i<255;i++)
{
printf("errno:%d(%s)\n",i,strerror(i));
}
return 0;
}
运行结果, 发现错误号超过134, 都是unkown, 即系统未定义.
$ ./errno_str
errno:0(Success)
errno:1(Operation not permitted)
errno:2(No such file or directory)
errno:3(No such process)
errno:4(Interrupted system call)
errno:5(Input/output error)
errno:6(No such device or address)
errno:7(Argument list too long)
errno:8(Exec format error)
errno:9(Bad file descriptor)
errno:10(No child processes)
errno:11(Resource temporarily unavailable)
errno:12(Cannot allocate memory)
errno:13(Permission denied)
errno:14(Bad address)
errno:15(Block device required)
errno:16(Device or resource busy)
errno:17(File exists)
errno:18(Invalid cross-device link)
errno:19(No such device)
errno:20(Not a directory)
errno:21(Is a directory)
errno:22(Invalid argument)
errno:23(Too many open files in system)
errno:24(Too many open files)
errno:25(Inappropriate ioctl for device)
errno:26(Text file busy)
errno:27(File too large)
errno:28(No space left on device)
errno:29(Illegal seek)
errno:30(Read-only file system)
errno:31(Too many links)
errno:32(Broken pipe)
errno:33(Numerical argument out of domain)
errno:34(Numerical result out of range)
errno:35(Resource deadlock avoided)
errno:36(File name too long)
errno:37(No locks available)
errno:38(Function not implemented)
errno:39(Directory not empty)
errno:40(Too many levels of symbolic links)
errno:41(Unknown error 41)
errno:42(No message of desired type)
errno:43(Identifier removed)
errno:44(Channel number out of range)
errno:45(Level 2 not synchronized)
errno:46(Level 3 halted)
errno:47(Level 3 reset)
errno:48(Link number out of range)
errno:49(Protocol driver not attached)
errno:50(No CSI structure available)
errno:51(Level 2 halted)
errno:52(Invalid exchange)
errno:53(Invalid request descriptor)
errno:54(Exchange full)
errno:55(No anode)
errno:56(Invalid request code)
errno:57(Invalid slot)
errno:58(Unknown error 58)
errno:59(Bad font file format)
errno:60(Device not a stream)
errno:61(No data available)
errno:62(Timer expired)
errno:63(Out of streams resources)
errno:64(Machine is not on the network)
errno:65(Package not installed)
errno:66(Object is remote)
errno:67(Link has been severed)
errno:68(Advertise error)
errno:69(Srmount error)
errno:70(Communication error on send)
errno:71(Protocol error)
errno:72(Multihop attempted)
errno:73(RFS specific error)
errno:74(Bad message)
errno:75(Value too large for defined data type)
errno:76(Name not unique on network)
errno:77(File descriptor in bad state)
errno:78(Remote address changed)
errno:79(Can not access a needed shared library)
errno:80(Accessing a corrupted shared library)
errno:81(.lib section in a.out corrupted)
errno:82(Attempting to link in too many shared libraries)
errno:83(Cannot exec a shared library directly)
errno:84(Invalid or incomplete multibyte or wide character)
errno:85(Interrupted system call should be restarted)
errno:86(Streams pipe error)
errno:87(Too many users)
errno:88(Socket operation on non-socket)
errno:89(Destination address required)
errno:90(Message too long)
errno:91(Protocol wrong type for socket)
errno:92(Protocol not available)
errno:93(Protocol not supported)
errno:94(Socket type not supported)
errno:95(Operation not supported)
errno:96(Protocol family not supported)
errno:97(Address family not supported by protocol)
errno:98(Address already in use)
errno:99(Cannot assign requested address)
errno:100(Network is down)
errno:101(Network is unreachable)
errno:102(Network dropped connection on reset)
errno:103(Software caused connection abort)
errno:104(Connection reset by peer)
errno:105(No buffer space available)
errno:106(Transport endpoint is already connected)
errno:107(Transport endpoint is not connected)
errno:108(Cannot send after transport endpoint shutdown)
errno:109(Too many references: cannot splice)
errno:110(Connection timed out)
errno:111(Connection refused)
errno:112(Host is down)
errno:113(No route to host)
errno:114(Operation already in progress)
errno:115(Operation now in progress)
errno:116(Stale file handle)
errno:117(Structure needs cleaning)
errno:118(Not a XENIX named type file)
errno:119(No XENIX semaphores available)
errno:120(Is a named type file)
errno:121(Remote I/O error)
errno:122(Disk quota exceeded)
errno:123(No medium found)
errno:124(Wrong medium type)
errno:125(Operation canceled)
errno:126(Required key not available)
errno:127(Key has expired)
errno:128(Key has been revoked)
errno:129(Key was rejected by service)
errno:130(Owner died)
errno:131(State not recoverable)
errno:132(Operation not possible due to RF-kill)
errno:133(Memory page has hardware error)
errno:134(Unknown error 134)
errno:135(Unknown error 135)
errno:136(Unknown error 136)
errno:137(Unknown error 137)
errno:138(Unknown error 138)
errno:139(Unknown error 139)
errno:140(Unknown error 140)
... 其后都是Unkown...
6. errno 在系统中是如何定义的?
请参考 errno 5 错误追踪
7. errno 的应用实例参考.
当一个系统调用或着库函数的调用失败时,将会由被调用函数设置错误代码errno。
当然你的函数在出错时也可以设置errno, 但应该保持与系统定义的意义一致. 不过一般你是不需要设置errno的
下面的程序演示了,只有在调用库函数不出错时(路径存在), 才能得到正确的可用内存数值.
$ cat main.cpp
#include <stdio.h>
#include <sys/statfs.h>
#include <errno.h>
#include <string.h>
int main()
{
struct statfs buf;
// 文件路径不存在,打印可用内存不会有正确结果,
// int ret=statfs("/home/hjj/notexist", &buf);
// 路径存在才会有正确输出, 这是我写本博客的初始原因
int ret=statfs("/home/hjj/", &buf);
printf("ret is %d\n",ret);
if(ret<0)
{
printf("error:%d(%s)\n",errno,strerror(errno));
return -1;
}
printf("free block avail:%ld(K bytes)\n",buf.f_bavail * buf.f_bsize/1024);
return 0;
}
运行结果:
$ ./statfs
ret is 0
free block avail:21930648(K bytes)
与 $ df 显示的一致
文件系统 1K-块 已用 可用 已用% 挂载点
/dev/nvme0n1p3 83558648 57337440 21930648 73% /home