文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>linux 1.0 内核注解 linux/kernel/printk.c

linux 1.0 内核注解 linux/kernel/printk.c

时间:2009-03-05  来源:taozhijiangscu

/********************************************
 *Created By: 陶治江
 *Date:       2009-3-3
 ********************************************/
 
#include <stdarg.h>
#include <asm/segment.h>
#include <asm/system.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#define LOG_BUF_LEN 4096   //循环的日志缓存,总共有4k的日志容量 static char buf[1024]; extern int vsprintf(char * buf, const char * fmt, va_list args);
extern void console_print(const char *);
#define DEFAULT_MESSAGE_LOGLEVEL 7 /* KERN_DEBUG */
#define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything more serious than KERN_DEBUG */
unsigned long log_size = 0;
//这个程序里面,其实这个变量是一个很重要的变量
//观察可以发现,当调用sys_syslog的时候它是不断
//递减的(而且如果log_size=0还要等待睡眠),而
//在printk写入日志的时候,它是不断增加的,两者之间
//使用的睡眠进行等待,从而进行了内核的同步了
struct wait_queue * log_wait = NULL;
int console_loglevel = DEFAULT_CONSOLE_LOGLEVEL;
static void (*console_print_proc)(const char *) = 0;
static char log_buf[LOG_BUF_LEN];
static unsigned long log_start = 0;
static unsigned long logged_chars = 0;  
// Number of chars produced since last read+clear operation
// 也的确是这样的,最终这个变量也只有在clear下才变为0
// 而printk下它是不断长的,记录了新加入的数据
//read kernel message ring buffer
/* Commands to sys_syslog:
 *  0 -- Close the log.  Currently a NOP.
 *  1 -- Open the log. Currently a NOP.
 *  2 -- Read from the log.
 *  3 -- Read up to the last 4k of messages in the ring buffer.
 *  4 -- Read and clear last 4k of messages in the ring buffer
 *  5 -- Clear ring buffer.
 *  6 -- Disable printk's to console
 *  7 -- Enable printk's to console
 * 8 -- Set level of messages printed to console*/
asmlinkage int sys_syslog(int type, char * buf, int len)
{
 unsigned long i, j, count;
 int do_clear = 0;
 char c;
 int error;
 if ((type != 3) && !suser()) //Only function 3 is allowed to non-root processes.
  return -EPERM;
  
 switch (type) { /*功能号*/
  case 0:  /* Close log */
   return 0;
  case 1:  /* Open log */
   return 0;
  case 2:  /* Read from log
      *这个功能不断等待直到内核日志缓冲不为空
      *读取的日志信息将消失(这些信息只能读一次)*/
   if (!buf || len < 0)
    return -EINVAL;
   if (!len)  //不读不当做错
    return 0;
    
   error = verify_area(VERIFY_WRITE,buf,len);
   if (error)
    return error;
   cli();
   while (!log_size) { //如果log_size==0,没有日志
    if (current->signal & ~current->blocked) {
     /*如果当前进程有非屏蔽信号,就打开中断后返回*/
     sti();
     return -ERESTARTSYS;
    }    //否则可中断睡眠等待,是不是在等待日志啊?对的
        //printk最后会唤醒它的
    interruptible_sleep_on(&log_wait);
   }
   i = 0;
   while (log_size && i < len) {
    /*观测来看log_buf是日志4k块的起始,而
     *log_start是日志内容的开始(注意的是
     *这个4k的缓冲是循环的哈)*/
    c = *((char *) log_buf+log_start); /*要读的第一个字符*/
    log_start++;
    log_size--;
    log_start &= LOG_BUF_LEN-1;   /*循环的解决方式*/
    sti();
    put_fs_byte(c,buf);  /*将内核中的日志内容放到用户缓冲区中*/
    buf++;
    i++;
    cli();     /*这里看出内核的日志操作是不允许中断的*/
   }
   sti();
   return i;  /*返回读取的字符个数*/
   
  case 4:  /* Read/clear last kernel messages */
   do_clear = 1;
     /*FALL THRU 因为4除了3的功能之外还要清除日志的
      *fall through是应该的*/
  case 3:  /* Read last kernel messages */
   if (!buf || len < 0)
    return -EINVAL;
   if (!len)
    return 0;
   error = verify_area(VERIFY_WRITE,buf,len);
   if (error)
    return error;
    
   count = len;
   if (count > LOG_BUF_LEN)
    count = LOG_BUF_LEN; /*最多读取4k的内容*/
    
   //感觉这里似乎是唯一有用到的地方 :-(
   //由于count不能比LOG_BUF_LEN大,所以即使
   //logged_chars比LOG_BUF_LEN 大,也不回超过LOG_BUF_LEN的
   if (count > logged_chars) 
    count = logged_chars;
    
   //因为是要最新的信息,所以读取的开头不应该是log_start了
   //而是计算出来的j了
   j = log_start + log_size - count;
   
   for (i = 0; i < count; i++) {
    c = *((char *) log_buf+(j++ & (LOG_BUF_LEN-1)));
    put_fs_byte(c, buf++);
   }
   if (do_clear)   /*清除标志*/
    logged_chars = 0; //这里也可以看出,不需要实际清空,维持一个好的
         //清晰的标记是很方便的
   return i;
  case 5:  /* Clear ring buffer */
   logged_chars = 0;
   return 0;
   
  case 6:  /* Disable logging to console
       * Disable printk's to console */
   console_loglevel = 1; /* only panic messages shown */
   return 0;
  case 7:  /* Enable logging to console
       * Enable printk's to console */
   console_loglevel = DEFAULT_CONSOLE_LOGLEVEL;
   return 0;
   
  case 8:
   if (len < 0 || len > 8)
    return -EINVAL;
   console_loglevel = len;
   return 0;
 }
 return -EINVAL;
}

asmlinkage int printk(const char *fmt, ...)
{
 va_list args;
 int i;
 char *msg, *p, *buf_end;
 static char msg_level = -1;
 long flags;
 save_flags(flags);
 cli();
 va_start(args, fmt);
 i = vsprintf(buf + 3, fmt, args); /* hopefully i < sizeof(buf)-4 */
 buf_end = buf + 3 + i;   //buf的大小最多是1024
 va_end(args); 
 
 for (p = buf + 3; p < buf_end; p++) {  
  msg = p; 
  if (msg_level < 0) {  //如果msg_level没有设置-对于刚进来的时候
   if ( //这里是从字串的开始<n>进行猜测的,如果失败了就
     //使用默认的msg_level
    p[0] != '<' ||
    p[1] < '0' ||
    p[1] > '7' ||
    p[2] != '>'
   ) {
    p -= 3;   //呃,这里刚好跳到了buf的头部了
    p[0] = '<';
    p[1] = DEFAULT_MESSAGE_LOGLEVEL - 1 + '0'; /* <6> */
    p[2] = '>';
   } else
    msg += 3;  //合法,msg指向的是字串(没有信息级别了)
   msg_level = p[1] - '0';
  }
  
  for (; p < buf_end; p++) {  //这里的p也是在变的,其实感觉外面的for
          //用的就不太好!!
          //Sorry,I am wrong!!因为这里读到了'\n'就
          //跳出循环了,外边的for是要的,主要的原因可能
          //是由于\n对屏幕进行的显示的要求了
   log_buf[(log_start+log_size) & (LOG_BUF_LEN-1)] = *p;  //全局变量
   
   //注意下面的这个句子,因为log_buf是4k的回卷的,
   //所以记录了写入的数据,如果超过了log_buf,那么
   //log_start就被覆盖了,就必须转移log_start了
   if (log_size < LOG_BUF_LEN) 
    log_size++;
   else
    log_start++;
    
   logged_chars++;
   if (*p == '\n')
    break;  
  }
  if (msg_level < console_loglevel && console_print_proc) {
   char tmp = p[1];
   p[1] = '\0';
   (*console_print_proc)(msg);  //应该是显示出来吧
   p[1] = tmp;
  }
  if (*p == '\n')
   msg_level = -1;
 }
 
 restore_flags(flags);
 wake_up_interruptible(&log_wait);  //唤醒等待的进程
 return i;
}
/*
 * The console driver calls this routine during kernel initialization
 * to register the console printing procedure with printk() and to
 * print any messages that were printed by the kernel before the
 * console driver was initialized.
 */
void register_console(void (*proc)(const char *))
{
 int i,j;
 int p = log_start;
 char buf[16];
 char msg_level = -1;
 char *q;
 console_print_proc = proc;  for (i=0,j=0; i < log_size; i++) {
  buf[j++] = log_buf[p];  //log_start
  p++;
  p &= LOG_BUF_LEN-1;   //回转
  if (buf[j-1] != '\n' && i < log_size - 1 && j < sizeof(buf)-1)
   continue;
   //'\n' 一句完了
   
  buf[j] = 0;
  q = buf;
  if (msg_level < 0) {  //这个好像对<n>结构很自信哦
   msg_level = buf[1] - '0';
   q = buf + 3;
  }
  if (msg_level < console_loglevel)
   (*proc)(q);   //调用这个函数
   
  if (buf[j-1] == '\n') //好像这个msg_level是以换行进行更改的
   msg_level = -1;
  j = 0;
 }
}
  文档地址:http://blogimg.chinaunix.net/blog/upfile2/090305140033.pdf
相关阅读 更多 +
排行榜 更多 +
爱是小事最新版

爱是小事最新版

休闲益智 下载
悬案2刹那惊颤游戏

悬案2刹那惊颤游戏

冒险解谜 下载
几何飞行内购修改版

几何飞行内购修改版

飞行射击 下载