嵌入式开发记录-补充01:linux内核同步

1、内核中的互斥与同步:

  互斥:从排他性角度;同步:偏重顺序

2、内核中的同步互斥机制:

  2.1、中断屏蔽:

local_irq_disable();
// 中断屏蔽临界区
local_irq_enable();

  2.2、自旋锁:

  临界区:不能有进程调度,执行时间短;

  上锁失败:自旋(100%的CPU占有率)

// 初始化锁
spin_lock_init(_lock)
spin_lock(& vcpu -> kvm -> mmu_lock)
// 临界区
spin_unlock(spinlock_t * lock)

  2.3、原子变量操作

atomic_t *v

int atomic_read(const atomic_t *v)
void atomic_set(atomic_t *v, int i)

void atomic_add(int i, atomic_t *v)  // 原子变量加i操作
void atomic_sub(int i, atomic_t *v)

void atomic_inc(atomic_t *v)    // 自增操作
void atomic_dec(atomic_t *v)

int atomic_dec_and_test(atomic_t *v)
int atomic_inc_and_test(atomic_t *v)

  2.4、信号量

  内核同步机制:解决多个任务同时访问一个共享资源引起的访问数据异步的问题;

  信号量:信号量会引起进程睡眠,因此适应于锁长时间被持有的情况;因此不能在中断中使用;

  1、信号量使用方式:

// 定义信号量
struct semaphore sem;

// 初始化信号量
void sema_init(struct semaphore *sem,int val);

// 初始化互斥信号量,只有一个资源的信号量,同时只有一个任务获得信号量
void init_MUTEX(struct semaphore *sem);
// 等同于
sema_init(struct semaphore* sem, 1);

/* 获取信号量 */
void down(struct semaphore* sem);  // 进入睡眠的任务,不可被信号打断
void down_interruptible(struct semaphore *sem);  // 进入睡眠的进程能够被信号打断,信号会导致该任务返回;
int down_trylock(struct semaphore* sem);  //如果丽可获取到锁,立刻放回;获取不到也不会导致该任务睡眠;

/* 释放信号量 */
void up(struct semaphore* sem);  // 释放信号量,唤醒等待者;

2.5、互斥锁:

struct mutex

mutex_init(mutex)
void mutex_destroy(struct mutex *lock)

mutex_lock(struct mutex *lock);
void mutex_unlock(struct mutex *lock);

int __must_check mutex_lock_interruptible(struct mutex *lock);

 

3、  睡眠与唤醒

wait_event(queue,condition)

wait_event_interruptible(queue,condition)

wait_event_timeout(queue,condition,timeout)

wait_event_interruptible_timeout(queue,condition,timeout)

queue: wait_queue_head_t
condition:睡眠唤醒条件
timeout:超时限制

调佣以上函数,进程会把自己进入queue的等待队列,然后睡眠;

唤醒:condition为1,并且调用唤醒函数;

  唤醒:

/* 唤醒所有给定队列上的进程 */
void wake_up(wait_queue_head_t* queue);

/* 唤醒所有给定队列上可中断的进程 */
void wake_up_interruptible(wait_queue_head_t* queue);

 

4、将设备或者文件映射到用户空间

char* data;  // 需要映射的内核内存
int myOpen(struct inode* p, struct file*p)
{
  int i=0;
  struct page* mypage;
  data = kzalloc(8096,GFP_KERNEL);
  for(i=0;i<8092;i++)
  {
      data[i] = i%255;  
  }  
  for(i=0;i<2;i++)
  {
      mypage = virt_to_page((void*)(data+(i*PAGE_SIZE)));
      SetPageReserved(mypage);      
  }  
  return 0;  
}
static int myMmap(struct file* f,struct vm_area_struct* vma)
{
    unsigned long phys, len;
    unsigned long pfn;
    
    phys = virt_to_phys((void*)data);   // 将虚拟地址转换物理地址
    len = vma->vma_end - vma_start;
    printk("vma end:%ld\n", vma->vma_end);
    printk("vma start:%ld\n", vma->vma_start);
    
    pfn = phys>> PAGE_SHIFT; // 得到物理块号;
    if(remap_pfn_range(vma,vma->vma_start,pfn,len,vma->vma_page_prot))
    {
        printk("remap error");
    }
    return 0;
}

应用程序:

  int fd = open("");
  void* buf = mmap(...,"fd");
  可直接修改读取buf中的数据; // 从设备或者文件映射过来的内存空间

 

posted @ 2022-04-17 18:11  笑不出花的旦旦  阅读(41)  评论(0编辑  收藏  举报