2012-06-28 20:13:46 lida2003 阅读数 940
  • ADC-1.13.ARM裸机第十三部分

    本期课程主要讲解AD转换相关的概念(如模拟量、数字量),AD转换涉及到的一些参数如模拟量量程、数字量位数精度(分辨率)、转换速率(MSPS)等,然后讲了S5PV210的AD控制器和主要寄存器,后带大家初级编写AD转换的裸机程序并完成调试优化。课程目标在于让大家掌握AD转换的概念、意义和编程实践。

    4270 人正在学习 去看看 朱有鹏

方法一:LINUX提供了一个查看配置的命令

(实际有相应的库函数)getconf


使用方法如下:

# getconf LONG_BIT

注:如果返回64,就表示为64位内核,否则应当返回32。


方法二:查看Linux初始化进程编译可执行文件属性

# file /sbin/init

注:如果返回64,就表示为64位内核,否则应当返回32。


方法三:查看系统配置

# uname -a

注:如果看到有i686_64或者类似的信息表示是64位的,没有则是32位的。

2018-07-18 16:59:38 owhfg 阅读数 265
  • ADC-1.13.ARM裸机第十三部分

    本期课程主要讲解AD转换相关的概念(如模拟量、数字量),AD转换涉及到的一些参数如模拟量量程、数字量位数精度(分辨率)、转换速率(MSPS)等,然后讲了S5PV210的AD控制器和主要寄存器,后带大家初级编写AD转换的裸机程序并完成调试优化。课程目标在于让大家掌握AD转换的概念、意义和编程实践。

    4270 人正在学习 去看看 朱有鹏
/**原子变量操作是Linux的一种简单同步机制,是一种在操作过程中不会被打断的操作.***/
/****其API和原子类型定义在include/asm/atomic.h文件中,使用汇编实现
****优点是编写简单;缺点是功能太简单,只能做计数操作,保护的东西太少,
***/

/*原子变量类型为atomic_t,atomic_t实际上是一个int类型的值,但由于处理器限制,
只能表示24位数的范围, 低8位设置成一个锁.*/

typedef struct{
    volatile int counter;
}atomic_t;

/*atomic_t类型初始化使用如下宏*/
atomic_t count = ATOMIC_INIT(0);

/*设置atomic_t变量的值使用如下宏*/
#define atomic_tset(v,i)    (((v)->counter)=i)

/*读取atomic_t变量的值使用如下宏*/
#define atomic_read(v)  ((v)->counter)

/*原子变量加减法,使用如下函数*/
atomic_add(int i, volatile atomic_t *v);    //将i值加到v中
atomic_sub(int i, volatile atomic_t *v);    //从v中减去i值

static inline void atomic_inc(volatile atomic_t *v);    //将v指向的变量加1
static inline void atomic_dec(volatile atomic_t *v);    //将v指向的变量减1

/*原子位操作,原子位操作不需要定义一个类似stomic_t的变量,只需要一个普通的变量指针*/
static inline void set_bit(int nr, volatile unsigned long *addr);   //将addr变量的第nr位设置为1
static inline void clear_bit(int nr, volatile unsigned long *addr); //将addr变量的第nr位设置为0
static inline void change_bit(int nr, volatile unsigned long *addr);    //将addr变量的第nr位设置为相反数
static inline int test_and_set_bit(int nr, volatile unsigned long *addr);   //将addr变量的第nr位设置为1,并返回未修改之前的值
static inline int test_and_clear_bit(int nr, volatile unsigned long *addr); //将addr变量的第nr位设置为0,并返回未修改之前的值
static inline int test_and_change_bit(int nr, volatile unsigned long *addr);    //将addr变量的第nr位设置为相反数,并返回未修改之前的值


/*单独的原子操作不能满足复杂的内核设计需要,Linux提供一些锁机制来避免竞争条件,最简单的一种就是自旋锁*/
/*自旋锁是一种简单的并发控制机制,其是实现信号量和完成量的基础*/

/*定义和初始化自旋锁*/
spinlocak_t lock = SPIN_LOCK_UNLOCKED;  //编译阶段通过宏来实现
void spin_lock_init(spinlock_t lock);   //使用函数动态地初始化

/*锁定自旋锁或叫获得自旋锁*/
//如果能够获得自旋锁则宏立刻返回;否则,这个锁会一直自旋在那里,直到该锁被释放
#define spin_lock(lock) _spin_lock(lock);   
/*释放自旋锁*/
#define spin_unlock(lock)   _spin_unlock(lock)  //释放lock自旋锁,调用该宏之后,锁立刻被释放

/****自旋锁等待不是讲进程挂起,而是不断地循环条件是否满足,满足则解锁,
*****所以自旋锁对系统性能有影响。程序不应该长时间持有自旋锁,它适合
*****短时间锁定的轻量级的轻量级加锁机制.*/


/***信号量只有当得到信号量的继承或者线程时才能够进入临界区.与自旋锁不同,
当进程不能获得信号量时,进程将自己加入等待队列睡眠,直到信号量被释放,进程才被唤醒.***/

/*信号量结构体*/
struct semaphore{
    spinlock_t  lock;   //用来对count变量起保护作用,当count要变化时,内部会锁定lock锁,修改完之后再释放锁
    unsigned int    count;  //等于0值,表示信号量被其他进程使用,现在不可用,但是wait_list队列中没有进程在等待信号量
                            //小于0值,表示至少有一个进程在wait_list队列中等待信号量
                            //大于0值,表示信号量是空闲的,程序可以使用这个信号量    
    struct list_head    wait_list;  //等待队列链表头,存放正在睡眠的进程链表
}

/*定义和初始化一个信号量*/
struct semaphore sema;
static inline void sema_init(struct semaphore *sem,int val);//初始化信号量,并设置sem中count值为val
#define init_MUTEX(sem) sema_init(sem,1)    //初始化一个count值为1的互斥信号量,  
#define init_MUTEX_LOCKED(sem)  sema_init(sem,0)    //初始化一个count值为0的信号量

/*锁定信号量*/
void down(struct semaphore *sem)
{
    unsigned long flags;

    spin_lock_irqsave(&sem->lock, flags);   //锁定信号量的自旋锁
    if (likely(sem->count > 0))
        sem->count--;                       //如果信号量可用,将count减1
    else
        __down(sem);                        //如果信号量不可用,挂起进程
    spin_unlock_irqrestore(&sem->lock, flags);  //释放自旋锁
}

/*释放信号量*/
void up(struct semaphore *sem)
{
    unsigned long flags;

    spin_lock_irqsave(&sem->lock, flags);   //锁定信号量自旋锁
    if (likely(list_empty(&sem->wait_list)))
        sem->count++;                       //如果等待队列为空,将count加1
    else
        __up(sem);                          //如果等待队列不为空,看下述内核代码,
    spin_unlock_irqrestore(&sem->lock, flags);  //释放自旋锁
}


static noinline void __sched __up(struct semaphore *sem)
{
    //获得等待队列下一个元素的首地址,涉及到内核经常用到了container of 宏,在另一篇博客有详细讲解
    //[container_of宏](https://blog.csdn.net/owhfg/article/details/81100532)
    struct semaphore_waiter *waiter = list_first_entry(&sem->wait_list,
                        struct semaphore_waiter, list);         
    list_del(&waiter->list);                //从等待队列中删除当前元素,涉及到链表的删除操作.
    waiter->up = 1;
    wake_up_process(waiter->task);                          //唤醒相应的进程
}

/***由对内核源码可以得出结论,在进程未调用down()函数时也可以调用up()函数,放出信号量,
****且up()函数每次只能唤醒最先进入等待队列的进程。
***/

/****Linux中提供一种机制,实现一个线程发送一个信号通知另外一个进程开始完成某个任务,
*****这种机制就是完成量.完成量的目的是告诉一个线程某个事件已经发生,和信号量比较类似,
*****但在这种线程通信情况下有更高的效率****/

/*完成量的结构体*/
struct completion{
    unsigned int done;      //等于0时,等待完成量的进程会进入等待状态
                            //大于0时, 表示等待完成量的函数可以立刻执行
    wait_queue_head_t wait; //等待队列的链表头,所有等待该完成量的进程组成一个链表结构
}

/*定义和初始化完成量*/
struct completion com;
static inline void init_completion(struct completion *x)
{
    x->done = 0;
    init_waitqueue_head(&x->wait);  //初始化等待队列头
}
/*还可以使用宏来定义和初始化一个完成量*/
#define DECLARE_COMPLETION(work)    \
    struct completion work = COMPLETION_INITIALIZER(work)
#define COMPLETION_INITIALIZER(work)
    {0, __WAIT_QUEUE_HEAD_INITIALIZER((work).wait)}

/*等待完成量*/
//该函数会执行一个不会被信号中断的等待,直到有线程完成这个完成量
void __sched wait_for_completion(struct completion *x); 
/*释放完成量*/
void complete(struct completion *x);        //唤醒一个等待的进程
void complete_all(struct completetion *x);  //唤醒所有的等待进程












2017-03-20 20:58:01 nicai888 阅读数 183
  • ADC-1.13.ARM裸机第十三部分

    本期课程主要讲解AD转换相关的概念(如模拟量、数字量),AD转换涉及到的一些参数如模拟量量程、数字量位数精度(分辨率)、转换速率(MSPS)等,然后讲了S5PV210的AD控制器和主要寄存器,后带大家初级编写AD转换的裸机程序并完成调试优化。课程目标在于让大家掌握AD转换的概念、意义和编程实践。

    4270 人正在学习 去看看 朱有鹏

    Linux系统,支持物理内存虚拟化,即进程并不直接在真实物理地址上寻址,而是由Linux内核为每一进程维护了一个特殊的虚拟地址空间(virtual address space)。这个地址空间是线性的,从0开始寻址,到某个最大值(不同操作系统或不同位数的系统可能不一样)。
    虚拟地址空间由许多页(page)组成。典型的页大小是4096 bytes(4K, 32位系统)和8192bytes(8K,64位系统)。每个页面都有有效(valid)和无效(invalid)两种状态,一个valid page和一个物理页或一些二级存储介质相关联,例如一个交换分区或磁盘上的文件。
    一个进程不能直接访问一个存储在二级存储中的页,除非这个页和物理内存中的页相关联的。如果进程尝试进行这样的访问,存储器管理单元(MMU)会产生页错误(page fault),内核会从二级存储换入需要的页面。例如你对磁盘文件进行读取,这就导致IO操作,当然这些操作是内核级的,对用户透明的。当然系统为了满足各进程对内存的需求(物理内存有限),也经常性的将物理页面换出到虚拟地址页面。
    说到这里,笔者联想到了一种开发调试过程中经常遇到错误:段错误(segmentation fault)。造成这种错误的原因是,对无效页面(invalid)的非法访问,它与页错误有根本的区别: 页错误是操作系统的一种机制,而段错误是访问未初始化的页面造成的。

2011-02-12 17:26:00 ccc135246 阅读数 53
  • ADC-1.13.ARM裸机第十三部分

    本期课程主要讲解AD转换相关的概念(如模拟量、数字量),AD转换涉及到的一些参数如模拟量量程、数字量位数精度(分辨率)、转换速率(MSPS)等,然后讲了S5PV210的AD控制器和主要寄存器,后带大家初级编写AD转换的裸机程序并完成调试优化。课程目标在于让大家掌握AD转换的概念、意义和编程实践。

    4270 人正在学习 去看看 朱有鹏

1.task是进程调度的最小单位

 

2.优先级,linux分两种优先级

 

3.i/o消耗型和cpu消耗型

 

4.可执行队列,每个cpu对应一个runqueue。

   runqueue包含多个优先级数组。

 

5.优先级数组,包含以下内容:

   a.总任务数

   b.优先级位数组

   c.每个优先级一个链表,所有的链表组成一个数组,也即优先级数组

Linux系统管理

阅读数 24396

没有更多推荐了,返回首页