linux设备:cdev和kobj_map

先看kobj_map相关的代码
涉及到的文件
<linux/kobj_map.h>
<drivers/base/map.c>
[objc] view plaincopy
print?
  1. typedef struct kobject *kobj_probe_t(dev_t, intint *, voidvoid *);  
  2. struct kobj_map;  
  3. int kobj_map(struct kobj_map *, dev_t, unsigned longstruct module *, kobj_probe_t *, int (*)(dev_t, voidvoid *), voidvoid *);  
  4. void kobj_unmap(struct kobj_map *, dev_t, unsigned long);  
  5. struct kobject *kobj_lookup(struct kobj_map *, dev_t, intint *);  
  6. struct kobj_map *kobj_map_init(kobj_probe_t *, struct mutex *);  
typedef struct kobject *kobj_probe_t(dev_t, int *, void *);
struct kobj_map;
int kobj_map(struct kobj_map *, dev_t, unsigned long, struct module *, kobj_probe_t *, int (*)(dev_t, void *), void *);
void kobj_unmap(struct kobj_map *, dev_t, unsigned long);
struct kobject *kobj_lookup(struct kobj_map *, dev_t, int *);
struct kobj_map *kobj_map_init(kobj_probe_t *, struct mutex *);

先看kobj_map结构体
[objc] view plaincopy
print?
  1. struct kobj_map {  
  2.     struct probe {  
  3.         struct probe *next;      /* 这样形成了链表结构 */  
  4.         dev_t dev;               /* 设备号 */  
  5.         unsigned long range;     /* 设备号的范围 */  
  6.         struct module *owner;  
  7.         kobj_probe_t *get;  
  8.         int (*lock) (dev_t, voidvoid *);  
  9.         voidvoid *data;              /* 指向struct cdev对象 */  
  10.     } *probes[255];  
  11.     struct mutex *lock;  
  12. }  
struct kobj_map {struct probe {struct probe *next;      /* 这样形成了链表结构 */dev_t dev;               /* 设备号 */unsigned long range;     /* 设备号的范围 */struct module *owner;kobj_probe_t *get;int (*lock) (dev_t, void *);void *data;              /* 指向struct cdev对象 */} *probes[255];struct mutex *lock;
}
结构体中有一个互斥锁lock,一个probes[255]数组,数组元素为struct probe的指针。
根据下面的函数作用来看,kobj_map结构体是用来管理设备号及其对应的设备的。
kobj_map函数就是将指定的设备号加入到该数组,kobj_lookup则查找该结构体,然后返回对应设备号的kobject对象,利用
利用该kobject对象,我们可以得到包含它的对象如cdev。
struct probe结构体中的get函数指针就是用来获得kobject对象的,可能不同类型的设备获取的方式不同,我现在就看过cdev的exact_match函数。

kobj_map函数
[objc] view plaincopy
print?
  1. int kobj_map(struct kobj_map *domain, dev_t dev, unsigned long range, struct module *module, kobj_probe_t *probe, int (*lock)(dev_t, voidvoid *), voidvoid *data)  
  2. {  
  3.     unsigned n = MAJOR(dev+range-1) - MAJOR(dev) + 1;  
  4.     unsigned index = MAJOR(dev);  
  5.     unsigned i;  
  6.     struct probe *p;  
  7.   
  8.     if (n > 255)     /* 若n > 255,则超出了kobj_map中probes数组的大小 */  
  9.         n = 255;  
  10.     p = kmalloc(sizeof(struct probe) * n, GFP_KERNEL);  /* 分配n个struct probe */  
  11.     if(p == NULL)  
  12.         return -ENOMEM;  
  13.     for(i = 0; i < n; i++, p++) {     /* 用函数的参数初始化probe */  
  14.         p->owner = module;  
  15.         p->get = probe;  
  16.         p->lock = lock;  
  17.         p->dev = dev;  
  18.         p->range = range;  
  19.         p->data = data;  
  20.     }  
  21.     mutex_lock(domain->lock);  
  22.     for(i = 0, p-=n; i < n; i++, p++, index++) {  
  23.         struct probe **s = &domain->probes[index % 255];  
  24.         while(*s && (*s)->range < range)  
  25.             s = &(*s)->next;  
  26.         p->next = *s;  
  27.         *s = p;  
  28.     }  
  29.     mutex_unlock(domain->lock);  
  30.     return 0;  
  31. }  
int kobj_map(struct kobj_map *domain, dev_t dev, unsigned long range, struct module *module, kobj_probe_t *probe, int (*lock)(dev_t, void *), void *data)
{unsigned n = MAJOR(dev+range-1) - MAJOR(dev) + 1;unsigned index = MAJOR(dev);unsigned i;struct probe *p;if (n > 255)     /* 若n > 255,则超出了kobj_map中probes数组的大小 */n = 255;p = kmalloc(sizeof(struct probe) * n, GFP_KERNEL);  /* 分配n个struct probe */if(p == NULL)return -ENOMEM;for(i = 0; i < n; i++, p++) {     /* 用函数的参数初始化probe */p->owner = module;p->get = probe;p->lock = lock;p->dev = dev;p->range = range;p->data = data;}mutex_lock(domain->lock);for(i = 0, p-=n; i < n; i++, p++, index++) {struct probe **s = &domain->probes[index % 255];while(*s && (*s)->range < range)s = &(*s)->next;p->next = *s;*s = p;}mutex_unlock(domain->lock);return 0;
}

dev_t的前12位为主设备号,后20位为次设备号。
n = MAJOR(dev + range - 1) - MAJOR(dev) + 1 表示设备号范围(dev, dev+range)中不同的主设备号的个数。
通常n的值为1。
从代码中的第二个for循环可以看出kobj_map中的probes数组中每个元素为一个struct probe链表的头指针。
每个链表中的probe对象有(MAJOR(probe.dev) % 255)值相同的关系。若主设备号小于255, 则每个链表中的probe都有相同的主设备号。
链表中的元素是按照range值从小到大排列的。
while循环即是找出该将p插入的位置。



kobj_unmap函数
[objc] view plaincopy
print?
  1. void kobj_unmap(struct kobj_map *domain, dev_t dev, unsigned long range)  
  2. {  
  3.     unsigned n = MAJOR(dev + range - 1) - MAJOR(dev) + 1;  
  4.     unsigned index = MAJOR(dev);  
  5.     unsigned i;  
  6.     struct probe *found = NULL;  
  7.   
  8.     if (n > 255)  
  9.         n = 255;  
  10.   
  11.     mutex_lock(domain->lock);  
  12.     for (i = 0; i < n; i++, index++) {  
  13.         struct probe **s;  
  14.         for (s = &domain->probes[index % 255]; *s; s = &(*s)->next) {  
  15.             struct probe *p = *s;  
  16.             if (p->dev == dev && p->range == range) {  
  17.                 *s = p->next;  
  18.                 if (!found)  
  19.                     found = p;  
  20.                 break;  
  21.             }  
  22.         }  
  23.     }  
  24.     mutex_unlock(domain->lock);  
  25.     kfree(found);  
  26. }  
void kobj_unmap(struct kobj_map *domain, dev_t dev, unsigned long range)
{unsigned n = MAJOR(dev + range - 1) - MAJOR(dev) + 1;unsigned index = MAJOR(dev);unsigned i;struct probe *found = NULL;if (n > 255)n = 255;mutex_lock(domain->lock);for (i = 0; i < n; i++, index++) {struct probe **s;for (s = &domain->probes[index % 255]; *s; s = &(*s)->next) {struct probe *p = *s;if (p->dev == dev && p->range == range) {*s = p->next;if (!found)found = p;break;}}}mutex_unlock(domain->lock);kfree(found);
}
在16行,找到对应设备号dev和range指定的probe对象后,退出,然后kfree释放空间。


kobj_lookup函数
[objc] view plaincopy
print?
  1. struct kobject *kobj_lookup(struct kobj_map *domain, dev_t dev, intint *index)  
  2. {  
  3.     struct kobject *kobj;  
  4.     struct probe *p;  
  5.     unsigned long best = ~0UL;  
  6.   
  7. retry:  
  8.     mutex_lock(domain->lock);  
  9.     for (p = domain->probes[MAJOR(dev) % 255]; p; p = p->next) {  
  10.         struct kobject *(*probe)(dev_t, intint *, voidvoid *);  
  11.         struct module *owner;  
  12.         voidvoid *data;  
  13.   
  14.         if (p->dev > dev || p->dev + p->range - 1 < dev)  
  15.             continue;  
  16.         if (p->range - 1 >= best)  
  17.             break;  
  18.         if (!try_module_get(p->owner))  
  19.             continue;  
  20.         owner = p->owner;  
  21.         data = p->data;  
  22.         probe = p->get;  
  23.         best = p->range - 1;  
  24.         *index = dev - p->dev;   /* 这个是用来干嘛的? */  
  25.         if (p->lock && p->lock(dev, data) < 0) {  
  26.             module_put(owner);  
  27.             continue;  
  28.         }  
  29.         mutex_unlock(domain->lock);  
  30.         kobj = probe(dev, index, data);  
  31.         /* Currently ->owner protects _only_ ->probe() itself. */  
  32.         module_put(owner);  
  33.         if (kobj)  
  34.             return kobj;  
  35.         goto retry;  
  36.     }  
  37.     mutex_unlock(domain->lock);  
  38.     return NULL;  
  39. }  
struct kobject *kobj_lookup(struct kobj_map *domain, dev_t dev, int *index)
{struct kobject *kobj;struct probe *p;unsigned long best = ~0UL;retry:mutex_lock(domain->lock);for (p = domain->probes[MAJOR(dev) % 255]; p; p = p->next) {struct kobject *(*probe)(dev_t, int *, void *);struct module *owner;void *data;if (p->dev > dev || p->dev + p->range - 1 < dev)continue;if (p->range - 1 >= best)break;if (!try_module_get(p->owner))continue;owner = p->owner;data = p->data;probe = p->get;best = p->range - 1;*index = dev - p->dev;   /* 这个是用来干嘛的? */if (p->lock && p->lock(dev, data) < 0) {module_put(owner);continue;}mutex_unlock(domain->lock);kobj = probe(dev, index, data);/* Currently ->owner protects _only_ ->probe() itself. */module_put(owner);if (kobj)return kobj;goto retry;}mutex_unlock(domain->lock);return NULL;
}

对cdev_add函数,这里的p->probe函数即是exact_match, p->lock为exact_lock函数。


kobj_map_init函数
[objc] view plaincopy
print?
  1. struct kobj_map *kobj_map_init(kobj_probe_t *base_probe, struct mutex *lock)  
  2. {  
  3.     struct kobj_map *p = kmalloc(sizeof(struct kobj_map), GFP_KERNEL);  
  4.     struct probe *base = kzalloc(sizeof(*base), GFP_KERNEL);  
  5.     int i;  
  6.   
  7.     if ((p == NULL) || (base == NULL)) {  
  8.         kfree(p);  
  9.         kfree(base);  
  10.         return NULL;  
  11.     }  
  12.   
  13.     base->dev = 1;  
  14.     base->range = ~0;  
  15.     base->get = base_probe;  
  16.     for (i = 0; i < 255; i++)  
  17.         p->probes[i] = base;  
  18.     p->lock = lock;  
  19.     return p;  
  20. }  
struct kobj_map *kobj_map_init(kobj_probe_t *base_probe, struct mutex *lock)
{struct kobj_map *p = kmalloc(sizeof(struct kobj_map), GFP_KERNEL);struct probe *base = kzalloc(sizeof(*base), GFP_KERNEL);int i;if ((p == NULL) || (base == NULL)) {kfree(p);kfree(base);return NULL;}base->dev = 1;base->range = ~0;base->get = base_probe;for (i = 0; i < 255; i++)p->probes[i] = base;p->lock = lock;return p;
}

在初始化一个kobj_map对象时,将probes指针全部指向同一个base。



下面是cdev部分。
文件:
<linux/cdev.h>
<fs/char_dev.c>

cdev.h
[objc] view plaincopy
print?
  1. struct cdev {  
  2.     struct kobject kobj;  
  3.     struct module *owner;  
  4.     const struct file_operations *ops;  
  5.     struct list_head list;  
  6.     dev_t dev;  
  7.     unsigned int count;  
  8. }  
  9. void cdev_init(struct cdev *, const struct file_operations *);  
  10. struct cdev *cdev_alloc(void);  
  11. void cdev_put(struct cdev *p);  
  12. int cdev_add(struct cdev *, dev_t, unsigned);  
  13. void cdev_del(struct cdev *);  
struct cdev {struct kobject kobj;struct module *owner;const struct file_operations *ops;struct list_head list;dev_t dev;unsigned int count;
}
void cdev_init(struct cdev *, const struct file_operations *);
struct cdev *cdev_alloc(void);
void cdev_put(struct cdev *p);
int cdev_add(struct cdev *, dev_t, unsigned);
void cdev_del(struct cdev *);

cdev_init函数
此函数首先调用kobject_init初始化cdev中的kobj,然后将cdev中的ops赋值。

cdev_alloc函数
先kzalloc分配一个cdev,然后用kobject_init初始化kobj

cdev_put函数

[objc] view plaincopy
print?
  1. void cdev_put(struct cdev *p)  
  2. {  
  3.     if (p) {  
  4.         struct module *owner = p->owner;  
  5.         kobject_put(&p->kobj);  
  6.         module_put(owner);  
  7.     }  
  8. }  
void cdev_put(struct cdev *p)
{if (p) {struct module *owner = p->owner;kobject_put(&p->kobj);module_put(owner);}
}

此函数调用kobject_put和module_put,好像它们的作用就是减少引用计数

cdev_add函数
[objc] view plaincopy
print?
  1. int cdev_add(struct cdev *p, dev_t dev, unsigned count)  
  2. {  
  3.     p->dev = dev;  
  4.     p->count = count;  
  5.     return kobj_map(cdev_map, dev, count, NULL, exact_match, exact_lock, p);  
  6. }  
int cdev_add(struct cdev *p, dev_t dev, unsigned count)
{p->dev = dev;p->count = count;return kobj_map(cdev_map, dev, count, NULL, exact_match, exact_lock, p);
}

主要是调用kobj_map将cdev放入cdev_map中。

cdev_del函数
[objc] view plaincopy
print?
  1. static void cdev_unmap(dev_t dev, unsigned count)  
  2. {  
  3.     kobj_unmap(cdev_map, dev, count);  
  4. }  
  5.   
  6. void cdev_del(struct cdev *p)  
  7. {  
  8.     cdev_unmap(p->dev, p->count);  
  9.     kobject_put(&p->kobj);  
  10. }  
static void cdev_unmap(dev_t dev, unsigned count)
{kobj_unmap(cdev_map, dev, count);
}void cdev_del(struct cdev *p)
{cdev_unmap(p->dev, p->count);kobject_put(&p->kobj);
}

这就不用说啥了。

LDD3上说“只要cdev_add返回了,我们的设备就‘活’了,它的操作就会被内核调用",那么这句奇妙的话到底是个什么意思?

下面是我目前了解的情况

据说在open一个字符设备文件时,最终总会调用chrdev_open。
下面是该函数的源码
注意inode->i_rdev中保存了设备编号,inode->icdev指向了cdev结构。
[objc] view plaincopy
print?
  1. static int chrdev_open(struct inode *inode, struct file *filp)  
  2. {  
  3.     struct cdev *p;  
  4.     struct cdev *new = NULL;  
  5.     int ret = 0;  
  6.   
  7.     spin_lock(&cdev_lock);  
  8.     p = inode->i_cdev;  
  9.     if (!p) {  
  10.         struct kobject *kobj;  
  11.         int idx;  
  12.         spin_unlock(&cdev_lock);  
  13.         kobj = kobj_lookup(cdev_map, inode->i_rdev, &idx);     
  14.         if (!kobj)  
  15.             return -ENXIO;  
  16.         new = container_of(kobj, struct cdev, kobj);   /* 找到字符设备的cdev */  
  17.         spin_lock(&cdev_lock);  
  18.         /* Check i_cdev again in case somebody beat us to it while 
  19.          we dropped the lock. */  
  20.         p = inode->i_cdev;  
  21.         if (!p) {  
  22.             inode->i_cdev = p = new;  
  23.             list_add(&inode->i_devices, &p->list);/* ZXG: 这是啥? */  
  24.             new = NULL;  
  25.         } else if (!cdev_get(p))  
  26.             ret = -ENXIO;  
  27.     } else if (!cdev_get(p))  
  28.         ret = -ENXIO;  
  29.     spin_unlock(&cdev_lock);  
  30.     cdev_put(new);  
  31.     if (ret)  
  32.         return ret;  
  33.   
  34.     ret = -ENXIO;  
  35.     filp->f_op = fops_get(p->ops);  
  36.     if (!filp->f_op)  
  37.         goto out_cdev_put;  
  38.   
  39.     if (filp->f_op->open) {  
  40.         ret = filp->f_op->open(inode, filp); /* 调用cdev->ops中的open函数 */  
  41.         if (ret)  
  42.             goto out_cdev_put;  
  43.     }  
  44.   
  45.     return 0;  
  46.   
  47.  out_cdev_put:  
  48.     cdev_put(p);  
  49.     return ret;  
  50. }  
static int chrdev_open(struct inode *inode, struct file *filp)
{struct cdev *p;struct cdev *new = NULL;int ret = 0;spin_lock(&cdev_lock);p = inode->i_cdev;if (!p) {struct kobject *kobj;int idx;spin_unlock(&cdev_lock);kobj = kobj_lookup(cdev_map, inode->i_rdev, &idx);   if (!kobj)return -ENXIO;new = container_of(kobj, struct cdev, kobj);   /* 找到字符设备的cdev */spin_lock(&cdev_lock);/* Check i_cdev again in case somebody beat us to it whilewe dropped the lock. */p = inode->i_cdev;if (!p) {inode->i_cdev = p = new;list_add(&inode->i_devices, &p->list);/* ZXG: 这是啥? */new = NULL;} else if (!cdev_get(p))ret = -ENXIO;} else if (!cdev_get(p))ret = -ENXIO;spin_unlock(&cdev_lock);cdev_put(new);if (ret)return ret;ret = -ENXIO;filp->f_op = fops_get(p->ops);if (!filp->f_op)goto out_cdev_put;if (filp->f_op->open) {ret = filp->f_op->open(inode, filp); /* 调用cdev->ops中的open函数 */if (ret)goto out_cdev_put;}return 0;out_cdev_put:cdev_put(p);return ret;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/403860.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

限定虚拟机可用的CPU利用率

Windows Server 2012姗姗来迟&#xff0c;最新的Hyper-V 3给我们带来更多的惊喜&#xff0c;后续三篇博文和大家共同学习虚拟机CPU竞争机制。 第一部分&#xff1a;分配给虚拟机的CPU资源 第二部分&#xff1a;限定虚拟机可用的CPU利用率 第三部分&#xff1a;争夺CPU资源优先级…

Windows 7 文件夹共享

今天搞了下windows 7下的文件共享&#xff0c;总是搞不定&#xff0c;虽然以前也偶尔有成功过&#xff0c;但未作记录&#xff0c;现在要搞一时搞不定&#xff0c;所以决定好好记录一下。 win7的文件夹共享搞得实在是太麻烦了(对于一般用户而言)&#xff0c;为了权限控制&#…

MYSQL学习笔记 (二)对数据库结构的增删改查

显示数据库 show databases; 选择数据库 use database;//其实database为数据库的名字 创建表 create table tbclass( id int not null auto_increment primary key, className varchar(20) not null unique, studentNum smallint not null )enginemyisam default charsetutf8 插…

将二进制文件bold转化为文件file

参考&#xff1a;bold和file互相转换 let files new window.File([this.blob], file.name, {type: file.type}) File()构造函数的前两个参数为必传

1.the linux device model--kobject kset学习笔记

http://blog.chinaunix.net/uid-22547469-id-4590385.html?utm_sourcejiancool Linux设备模型就是一栋规模宏大的建筑&#xff0c;为了构建它&#xff0c;需要基本的建筑材料钢筋&#xff1a;kobject、若干钢筋组成的钢架结构&#xff1a;kset&#xff0c;还需要一种机制sysfs…

带格式化参数的strcat宏定义

#include <stdio.h>#include <iostream>#include <string.h>using namespace std;// 带格式化参数的strcat宏定义#define Strcat(x, fmt, ...) sprintf(x, "%s" #fmt, x, __VA_ARGS__)int main(void){char buf[200];for(int k 0; k < 4; k){me…

微信公众号开发笔记1-获取Access Token

获取你的Access Token a&#xff09;可以采用网址的形式&#xff1a; 用appid和appsecert获得access token&#xff0c;接口为https://api.weixin.qq.com/cgi-bin/token?grant_typeclient_credential&appid你的APPID&secret你的APPSECRET 替换中间的你的APPID和APPSEC…

mii-tool与ethtool的用法详解

From: http://blog.chinaunix.net/uid-20639775-id-154546.html 1、mii-tool 配置网络设备协商方式的工具&#xff1b; 感谢原文作者&#xff01;原文地址&#xff1a;http://ygning.blog.com.cn/archives/2007/2153373.shtml 1.1 mii-tool 介绍&#xff1b; mii-tool - v…

linux学习wdlinux学堂

wdlinux学堂是什么?wdlinux学堂是一个学习Linux系统的学习计划,主要是linux系统的使用,服务器配置,架构,维护,优化,运维等等以wdOS系统为例做讲解,通过一些通俗的语言,结合自己的一些经验,来写一些教程或文档抛开书本的长篇大论,更多注重实践与操作每周五天,每天至少一课/一个…

ant更改主题色报错Inline JavaScript is not enabled. Is it set in your options? vue ant主题色更改 vue-cli3

问题&#xff1a;使用vue-cli3更改ant的主题色时候报错&#xff1a;Inline JavaScript is not enabled. Is it set in your options? 原因&#xff1a;我的问题是less-loader依赖包的版本为5.0.0&#xff0c;而官方要求必须是6.0.0&#xff1b; ERROR Failed to compile …

【Linux】文件操作系统调用

一. 文件描述符 在Linux下使用文件描述符来表示设备文件和普通文件。文件描述符是一个整型的数据&#xff0c;所有对文件的操作都通过文件描述符实现。文件描述符的范围是0~OPEN_MAX&#xff0c;系统中有3个已经分配的文件描述符&#xff0c;即标准输入、标准输出、和标准错误&…

sysfs接口函数的建立_DEVICE_ATTR

最近在弄Sensor驱动&#xff0c;看过一个某厂家的成品驱动&#xff0c;里面实现的全都是sysfs接口&#xff0c;hal层利用sysfs生成的接口&#xff0c;对Sensor进行操作。说道sysfs接口&#xff0c;就不得不提到函数宏 DEVICE_ATTR原型是#define DEVICE_ATTR(_name, _mode, _sho…

ant中table表格的多选框如何清空

项目需求&#xff1a;表格前加一列多选框&#xff0c;可以做多选和提交&#xff0c;还可以在提交后、重置或者翻页后对多选框清空 使用的组件是ant中下的可操作选择的table&#xff1b;这样我们就知道复选框选中的那些数据id&#xff0c;其实就是selectedRowKeys数组里的id&am…

SCCM 2012系列1 服务器准备上

各位您好&#xff0c;今天我将开始给大家分享微软最新的SCCM 2012系列文章&#xff0c;让大家逐步了解在企业内如何搭建SCCM 2012的同时&#xff0c;了解各个功能模块&#xff0c;对应自己的企业环境来看&#xff0c;那些功能是您现在所需要的。当然还可以看看SCCM 2012比之前…

linux内核源代码分析----内核基础设施之klist

概述klist是list的线程安全版本&#xff0c;他提供了整个链表的自旋锁&#xff0c;查找链表节点&#xff0c;对链表节点的插入和删除操作都要获得这个自旋锁。klist的节点数据结构是klist_node,klist_node引入引用计数&#xff0c;只有点引用计数减到0时才允许该node从链表中移…

近期H5项目开发小结

前言&#xff1a;2016差不多又过了半啦&#xff0c;最近参与了公司好几个h5项目&#xff08;严格来说&#xff0c;也只能算是推广页面活动&#xff09;。主要是新品牌的推广需要&#xff0c;当然也有给公司以前老客户做的案例。今天主要总结下为新品牌开发的2个h5推广&#xff…

vue-cli3中的vue.config.js配置

vue-cli3中的vue.config.js配置 我的跨域是配置通过chrome浏览器的跨域设置&#xff0c;前端修改跨域问题&#xff0c;以此解决跨域的&#xff0c; 故如果需要配置代理&#xff0c;就看proxy部分&#xff1b; const path require(path) const resolve (dir) > path.join…

获取python版本

import sys# global variablepyVersion 2 # set default python version to 2.x# init global variable(s)def init():global pyVersionpyVersion sys.version_info[0] # get major version of pythondef test():print(pyVersion)if __name__ __main__:init()test()运行情况…

会计的思考(37):“弱水三千,只取一瓢饮”--业务人员的财务意识

关键字: 会计体系 财务意识 投入产出 "任凭弱水三千&#xff0c;我只取一瓢饮"&#xff0c; 出自《红楼梦》,第九十一回里&#xff0c;贾宝玉曾经这样语带机锋地试图去化解林黛玉刚刚上来的醋劲。本文以此引出对业务人员的财务意识的思考。 成功企业家&#xff0c;如…

编译QtAV工程库

去https://github.com/wang-bin/QtAV下载源代码 去https://sourceforge.net/projects/qtav/files/depends/QtAV-depends-windows-x86%2Bx64.7z/download下载依赖库QtAV-depends-windows-x86x64.7z 将里面的include目录内容和lib内容分别拷贝到Qt的include和lib目录下 QtAV解压后…