SmlOS四-FIFO缓冲区实现

  • 内容
  • 评论
  • 相关

先进先出队列

FIFO(First in First out)

结构体

struct FIFO32 
{
    int *buf;       //缓冲区指针
    int p;          //下一个数据写入位置
    int q;          //下一个数据读出位置
    int size;       //缓冲区的总字节数
    int free;       //缓冲区的空闲字节数
    int flags;      //记录缓冲区是否溢出
    struct TASK *task;  //当队列缓冲区写入数据时需要唤醒的任务
};

相关操作函数

//缓冲区初始化函数 
void fifo32_init(struct FIFO32 *fifo, int size, int *buf, struct TASK *task)
{
    fifo->size = size;
    fifo->buf = buf;
    fifo->free = size; 
    fifo->flags = 0;
    fifo->p = 0; //下一个数据写入位置 
    fifo->q = 0; //下一个数据读出位置
    fifo->task = task; 
    return;
}

//缓冲区写入函数
int fifo32_put(struct FIFO32 *fifo, int data)
{
    //如果缓冲区已满 
    if (fifo->free == 0)
    {               
        fifo->flags |= FLAGS_OVERRUN;
        return -1;
    }
    fifo->buf[fifo->p] = data;      
    fifo->p++;
    if (fifo->p == fifo->size) 
    {
        fifo->p = 0;
    }
    fifo->free--;   
     //如果有需要唤醒的任务
    if (fifo->task != 0)
    {               
        //如果任务处于休眠 
        if (fifo->task->flags != 2)
        { 
            task_run(fifo->task, -1, 0); 
        }
    }
    return 0;
}

//缓冲区读出函数
int fifo32_get(struct FIFO32 *fifo)
{
    int data;
    //缓冲区为空 没有数据可读 
    if (fifo->free == fifo->size) 
    {
        return -1;
    }
    data = fifo->buf[fifo->q];          
    fifo->q++;                      
    if (fifo->q == fifo->size)
    {
        fifo->q = 0;
    }
    fifo->free++;                   
    return data;
}

简单来说就是在一块缓冲区上,有一个指针指向写入的地址,一个指针指向读取的地址,如果写入满了,则该写入的数据会被丢弃。

从而形成一个IO环。

代码和原理是比较简单的。

但是解决的问题却是不简单的。

在这里主要解决了两个问题:


鼠标中断数据的处理

因为中断函数的特殊性,中断中不能处理过多事情,比如说在鼠标中断的时候,就会将鼠标的数据(移动,按键信息)直接塞进FIFO结构体,然后就退出中断处理函数。

等待到内核线程调度的时候自行读取FIFO中的数据,操作显存移动鼠标,窗体等等操作。

这样的好处是,即使中断频繁发生,内核线程都无力处理的时候,顶多会丢弃一些数据,但不会影响系统正常运行。


进程/线程间消息通讯

现在的设计是每个线程都有自己的一个FIFO结构体用于存在通讯消息。

向线程发送消息就是向该进程FIFO结构体写入数据。

等该线程有执行机会的时候,自行读取处理,这样这个系统的设计都是基于消息的异步通知机制,和现代的操作系统思想设计一致。