解读PTR_ERR,ERR_PTR,IS_ERR

        我们知道内核有些函数是返回指针的,如Kmalloc分配内存,如果分配不到内核就会返回NULL指针,这样我们可以通过判断是否是NULL指针来判断Kmalloc执行成功与否。但是有些函数返回错误时,我们不仅需要知道函数错了,还需要知道错在哪里了,也就是说我们要或得错误码。在用户空间编程的时候,因为每个线程都有一个error变量,我们可以通过访问这个变量来得到错误码。但是在内核就没有这个变量,所以不能这样或得函数执行的错误码。那么聪明的内核开发着就根据内核的地址空间特点用了一种新的方法来或得错误码,那就是PTR_ERR,ERR_PTR,IS_ERR这三个宏,暂时先不说这三个宏怎么用,我们来看一下错误码与内核地址空间的特点。

    基本的错误码在内核中的errno-base.h中,如下:


 
 
  1. #define EPERM 1 /* Operation not permitted */
  2. #define ENOENT 2 /* No such file or directory */
  3. #define ESRCH 3 /* No such process */
  4. #define EINTR 4 /* Interrupted system call */
  5. #define EIO 5 /* I/O error */
  6. #define ENXIO 6 /* No such device or address */
  7. 。。。。。。。
  8. #define EFBIG 27 /* File too large */
  9. #define ENOSPC 28 /* No space left on device */
  10. #define ESPIPE 29 /* Illegal seek */
  11. #define EROFS 30 /* Read-only file system */
  12. #define EMLINK 31 /* Too many links */
  13. #define EPIPE 32 /* Broken pipe */
  14. #define EDOM 33 /* Math argument out of domain of func */
  15. #define ERANGE 34 /* Math result not representable */
        在不同的体系结构中也有一些err的宏定义,但是内核规定总的大小不能超过4095.说完了e错误码,然后在说一下内核的地址空间。我们知道Linux是基于虚拟内存的内核,所以CPU访问的是线性地址,而线性地址需要通过页表来转化成物理地址,如若一个线性地址的页表不存在的话会发生缺页异常。Linux在内核地址空间映射了大于0xc0000000的所有可用线性地址,而对于小于0xc0000000的线性地址在内核态是没有页表的,内核也从不使用小于0xc0000000的线性地址。也就是说内核返回指针的函数,如果执行正确,他返回的指针的大小绝对不会小于0xc0000000。如果小于这个那么肯定是错误的。所以可以利用这一点。内核函数都遵守一个约定,那就是如果不能返回正确的指针,那么就返回错误的,我们把返回的错误指针作为错误码。因为错误码都是整数,而返回的是指针,所以需要强制转换一下,这就诞生了这三个宏PTR_ERR,ERR_PTR,IS_ERR。这三个宏(内联函数)的定义在err.h中

 
 
  1. #define MAX_ERRNO 4095
  2. #ifndef __ASSEMBLY__
  3. #define IS_ERR_VALUE(x) unlikely((x) >= (unsigned long)-MAX_ERRNO)
  4. static inline void *ERR_PTR(long error)
  5. {
  6. return ( void *) error;
  7. }
  8. static inline long PTR_ERR(const void *ptr)
  9. {
  10. return ( long) ptr;
  11. }
  12. static inline long IS_ERR(const void *ptr)
  13. {
  14. return IS_ERR_VALUE(( unsigned long)ptr);
  15. }
        判断是否为错误指针也是很简单unlikely((x) >= (unsigned long)-MAX_ERRNO),这里问什么是大于简单说一下,以为错误码在返回的时候都去负数了,负数大的他的绝对值就小了。就是这个道理。至于这里为什么是4095,那就是内核约定的了,注意这里与什么页面大小没有一点关系,内核完全可以约定0xbfffffff,也是可以的,因为小于0xc0000000的线性地址都是错误的。这三个宏这样用。首先是一个返回指针的内核函数,比如 :

 
 
  1. struct device *foo()
  2. {
  3. ...
  4. if(...) { //错误了
  5. return ERR_PTR(-EIO);
  6. }
  7. }
        我们在调用这个函数的时候:

 
 
  1. struct deviced
  2. dfoo();
  3. ifIS_ERR( d)) {
  4. long err = PTR_ERR(d);
  5. printk( "errno is %d\n", err);
  6. }
        这样就可以提取错误码,然后根据错误码再做什么处理就由具体的驱动来处理了。我感觉其实将内核的机构与原理理解清楚了,内核的一些技巧就非常好理解了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于DOS的多任务系统的实现 #include<stdio.h> #include<stdlib.h> #include <time.h> #include<dos.h> /*定义TCB状态*/ #define FINISHED 0 #define RUNNING 1 #define READY 2 #define BLOCKED 3 #define NTCB 5 /*定义最大空闲TCB个数*/ #define TC 2 /*定义时间片长度*/ #define NBUF 6 /*定义缓冲区大小*/ #define GET_INDOS 0x34 #define GET_CRIT_ERR 0x5d06 struct TCB{ unsigned char *stack; /*线程堆栈起始地址*/ unsigned ss; /*堆栈段址*/ unsigned sp; /*堆栈指针*/ char state; /*线程状态*/ char name[15]; /*线程外部标识符*/ struct TCB *next; }tcb[NTCB]; /*初始化堆栈时使用*/ struct int_regs{ unsigned bp, di, si, ds, es, dx, cx, bx, ax, ip, cs, flags, off, seg; }; char fpub[3]; int current= -1; /*定义一个当前TCB下标的全局变量*/ int timecount = 0; /*定义时间片*/ char far *indos_ptr = 0; /*该指针变量存放INDOS表示的地址*/ char far *crit_err_ptr = 0; /*该指针变量存放严重错误标志的地址*/ void interrupt (*old_int8)(void);/*旧的时钟中断处理程序*/ typedef int (far *codeptr)(void); /*定义了一个函数指针类型*/ int buffer[NBUF] = {-1,-1,-1,-1,-1,-1}; /*生产者消费者中的缓冲区*/ int in = 0; int out = 0; typedef struct{ int value; struct TCB *wq; }semaphore; semaphore mutex={1,NULL},empty={NBUF,NULL},full={0,NULL},Mutex2={1,NULL}; /*生产者消费者中的信号量*/ void InitDos(void) { union REGS regs; struct SREGS segregs; regs.h.ah = GET_INDOS; intdosx(&regs,&regs,&segregs); indos_ptr = MK_FP(segregs.es,regs.x.bx); if(_osmajor<3) crit_err_ptr = indos_ptr+1; else if(_osmajor==3 && _osminor==0) crit_err_ptr = indos_ptr-1; else{ regs.x.ax = GET_CRIT_ERR; intdosx(&regs,&regs,&segregs); crit_err_ptr = MK_FP(segregs.ds,regs.x.si); } } int DosBusy(void) { if(indos_ptr && crit_err_ptr) return (*indos_ptr || *crit_err_ptr); else return -1; } int finished(void) { int i; for(i=1; i<NTCB; i++) if(tcb[i].state != FINISHED) return 0; return 1; } int Seeknext() { int i,ks; i=current+1; ks=0; disable(); while(ks<NTCB) { if(tcb[i].state==READY) { return i; } i++; ks++; i=i%NTCB; } printf("Seeknext tcb is error!!\n"); enable(); } void interrupt my_swtch(void) { disable();/*开中断*/ /*保护正在执行的线程current的现场,暂停它的执行*/ tcb[current].ss=_SS; tcb[current].sp=_SP; if(tcb[current].state==RUNNING) tcb[current].state=READY; /*找到新的就绪线程i*/ current=Seeknext(); tcb[current].state=RUNNING; /*切换堆栈,恢复线程i的现场,把CPU分派给它*/ _SS=tcb[current].ss; _SP=tcb[current].sp; /*重新开始计时*/ timecount=0; enable();/*关中断*/ } void interrupt new_int8(void) { /*调用原来的时钟中断服务程序*/ (*old_int8)(); /*进行计时*/ timecount++; /*当前线程的时间片到否*/ if(timecount >= TC) if(!DosBusy()) { /*调用my_swtch进行重新调度*/ my_swtch(); } } void Destroy(int i) { if(tcb[i].state==RUNNING) { disable(); tcb[i].state=FINISHED; free(tcb[i].stack); enable(); } return; } void over(void) { Destroy(current); printf("%s is finished!\n", tcb[current].name); my_swtch(); } void tcb_state() { int i; printf("These are the information of all threads: \n"); for(i=0;i<NTCB-1;i++) { printf("the key word of the thread is : %d\n the name of thread is : %s\n the state of the thread is ",i,tcb[i].name); switch(tcb[i].state) { case (1): printf("Running \n");break; case (2): printf("Ready \n");break; case (3): printf("Blocked\n");break; case (0): printf("Finished\n");break; } } } /*创建线程*/ int create(char *name, codeptr code, int stacklen) { int i = 0; struct int_regs *temp; while(tcb[i].state != FINISHED) /*查找空闲TCB块*/ i++; if(i == NTCB) return -1; /*没有空闲TCB块可用*/ strcpy(tcb[i].name, name); tcb[i].state = READY; tcb[i].stack = (unsigned char*)malloc(stacklen); /*为新线程分配私有堆栈空间*/ tcb[i].stack = tcb[i].stack + stacklen; /*初始化新线程的私有堆栈*/ temp = (struct int_regs *)tcb[i].stack-1; temp->ds = _DS; temp->es = _ES; temp->flags = 0x200; temp->ip = FP_OFF(code); temp->cs = FP_SEG(code); temp->off = FP_OFF(over); /*将over函数压入堆栈,线程结束自动执行*/ temp->seg = FP_SEG(over); tcb[i].ss = FP_SEG(temp); tcb[i].sp = FP_OFF(temp); return i; } void block(semaphore *sem) { struct TCB *p; disable(); tcb[current].state = BLOCKED; p = sem->wq; if(p == NULL){ sem->wq = &tcb[current]; } else{ while(p->next != NULL) p = p->next ; p->next = &tcb[current]; } tcb[current].next = NULL; my_swtch(); enable(); } void wakeup(semaphore *sem) { struct TCB *p; disable(); p = sem->wq; if(p != NULL){ p->state = READY; sem->wq = sem->wq->next; } enable(); } void wait(semaphore *sem) { disable(); sem->value = sem->value - 1; if(sem->value < 0) { printf("\nthe thread of %s is blocked\n",tcb[current].name); block(sem); } enable(); } void signal(semaphore *sem) { disable(); sem->value = sem->value + 1; if(sem->value <= 0) wakeup(sem); enable(); } void proceducer() { int i, j, k; for(i = 1; i <=13;i++){ wait(&empty); wait(&mutex); buffer[in] = i*i; printf("%s puts a number of %d in the buffer \n",tcb[current].name, buffer[in]); /*for(j=0; j<10000; j++) for(k=0; k<10000; k++);*/ in = (in +1) % NBUF; signal(&mutex); signal(&full); } } void consumer() { int i, j, k; for(i = 1; i<=7;i++){ wait(&full); wait(&mutex); printf("consumer gets the number of %d from the buffer\n", buffer[out]); buffer[out] = -1; /*for(j=0; j<1000; j++) for(k=0; k<10000; k++);*/ out = (out+1) % NBUF; signal(&mutex); signal(&empty); } } void f1() { int i,j,k; wait(&Mutex2); strcpy(fpub,"f1"); signal(&Mutex2); for(i=1;i<=22;i++) { wait(&Mutex2); printf("%s is running !\n",fpub); signal(&Mutex2); for(j=0;j<10000;j++) for(k=0;k<10000;k++); } } void f2() { int i,j,k; wait(&Mutex2); /*做放入数的操作*/ strcpy(fpub,"f2"); signal(&Mutex2); for(i=1;i<=33;i++) { wait(&Mutex2); printf("%s is running !\n",fpub); signal(&Mutex2); for(j=0;j<10000;j++) for(k=0;k<10000;k++); } } void InitTcb()/*TCB的初始化*/ { int i; for(i=0;i<NTCB;i++) { tcb[i].state=FINISHED; tcb[i].name[0]='\0'; tcb[i].next=NULL; } } int main(void) { InitDos(); InitTcb(); old_int8 = getvect(8); strcpy(tcb[0].name, "main"); tcb[0].state = RUNNING; current = 0 ; create("proceducerOne", (codeptr)proceducer, 1024); create("consumer", (codeptr)consumer, 1024); /*create("proceducerTwo", (codeptr)proceducer, 1024); create("f1",(codeptr)f1,1024); create("f2",(codeptr)f2,1024);*/ tcb_state(NTCB); setvect(8, new_int8); my_swtch(); while(!finished()) ; strcpy(tcb[0].name, "\0"); tcb[0].state = FINISHED; setvect(8, old_int8); printf("\n"); tcb_state(NTCB); printf("\nMulti_task system terminated.\n"); getchar(); return 0; }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值