Notes
main
main
  • Introduction
  • linuxKernel
    • tips
    • make_help
    • old linux
      • compile_linux0.11
      • TestEnvironment
      • load_setup
      • get_hard_data
    • list
    • plist
    • fifo
    • idr
    • xarray
    • rbtree
    • maple_tree
    • syscall
    • bitmap
    • page
    • page_flags
    • page_size
    • page mapcount
    • page refcount
    • folio
    • slub
      • proc_slabinfo
      • slub_theory
      • kmalloc_kfree
      • kmem_cache
      • slab_alloc
      • slab_free
      • proc_meminfo_SReclaimable_SReclaimable
    • vmalloc
    • brk
    • mmap
    • mremap
    • mprotect
    • madvise
    • read
    • write
    • shmem
    • huge_page
    • page_fault
    • rmap
    • lru
    • multi-gen-LRU
    • page_reclaim
    • page_cache
    • page_table
    • rcu
    • kvm
    • aarch64_boot
    • tracing_system
    • cache_coherence_and_memory_consistency
    • cpu_speculates
    • mmap_lock
    • per-vma_lock
    • cgroup
    • symbol
    • campact
    • page_ext
    • mempool
    • kernelstack
    • filesystem
    • io_stack
    • workingset
    • ioremap
    • sched_period
  • linuxDebug
    • openocd_openjtag
    • i2c_tools
    • objdump
    • addr2line
    • gdb_useage
    • debug_linux_kernel_via_gdb
    • debug_linux_module_via_gdb
    • early_boot
    • sequentially_execute
    • dynamic_debug
    • research_linuxKernel_by_patch
    • tracefs
    • ebpf
    • bpftrace
    • perf
    • flame_graph
    • crash
    • ASAN_HWASAN_MTE_check_mem_bug
    • page_owner
    • vmtouch
    • fio
    • benchmark
  • linuxSystem
    • common
      • system_version
      • procfs
      • proc_sys_vm
      • cmd_ps
      • makefile
      • file_descriptor
      • psi
      • ulimit
      • top
      • delay_accounting
    • ubuntu
      • custom_kernel
      • get_cmd_src
      • record_ssh_info
      • log
      • run_custom_script
      • repo
      • cockpit
      • nfs
      • tftp
      • misc
    • fedora
      • system_upgrade
      • custom_kernel
      • lvextend
      • yt-dlp
      • jellyfin
  • linuxDriver
    • i2c_peripherals_driver
    • spi_peripherals_driver
    • gpio_subsystem
    • IRQ_driver
    • blockIO_unblockIO_async
    • linux_own_driver
    • misc_device
    • input_device
    • timer
    • atomic_spinlock_semaphore_mutex
    • lcd
    • touch_screen
    • debugfs
    • v4l2
    • mmap
  • hardware
    • paging_mmu_pt
    • iommu
  • process_thread_scheduler
    • scheduler01
    • scheduler02
    • scheduler03
    • scheduler04
    • scheduler05
    • scheduler06
  • memory_management
    • mm1
    • mm2
    • mm3
    • mm4
    • mm5
  • input_output_filesystem
    • io_fs_01
    • io_fs_02
    • io_fs_03
    • io_fs_04
  • lock_and_lockup_detector
    • general_lock
    • hung_task
    • softLockup_hardLockup
    • crash_experiment
  • MIT_6.S081
    • 6.S081_Operating_System_Engineering
    • Schedule.md
    • Class
      • Overview
      • Administrivia
    • Labs
      • Tools
      • Guidance
      • startup
      • syscall
      • page_table
      • Calling_Convention
      • traps
    • xv6
      • xv6
    • References.md
  • qemu
    • qemu_buildroot
    • qemu_busybox.md
    • Serial.md
    • demo_mini2440
      • 0_compilation_error_summary
      • 1_compilation_steps
      • 2_operation_mode
      • 3_transplant_tools_libraries
      • 4_tools_use
      • reference_website
  • tools
    • getKernelSourceCodeList
    • nat
    • shell
    • translating
    • YouCompleteMe
    • cscope
    • global
    • vscode
    • vim
    • binary
    • markdown
    • draw
    • git
    • tig
    • tmux
    • mail_client
    • download_patchset_from_LKML
    • minicom
    • clash
  • other
    • interview
    • interview_c_base
    • know_dontknow
    • Stop-Ask-Questions-The-Stupid-Ways
    • How-To-Ask-Questions-The-Smart-Way
    • docker
    • buildroot
    • rv32_to_rv64
Powered by GitBook
On this page
  • 阻塞IO
  • 1. 创建 struct file_operations 变量
  • 2. 创建阻塞IO
  • 3. 唤醒
  • 4. 编写应用程序
  • 非阻塞IO
  • 1. 创建 struct file_operations 变量
  • 2. 创建非阻塞IO
  • 3. 唤醒
  • 4. 编写应用程序
  • 异步通知
  • 1. 创建 struct file_operations 变量
  • 2. 创建异步通知
  • 3. 唤醒
  • 4. 编写应用程序

Was this helpful?

  1. linuxDriver

blockIO_unblockIO_async

linux kernel 阻塞IO/非阻塞IO/异步通知的编写,都分为三步:

  1. 创建 struct file_operations 变量

  2. 创建 阻塞IO/非阻塞IO/异步通知

  3. 唤醒

  4. 编写应用程序

阻塞IO

1. 创建 struct file_operations 变量

const struct file_operations xxx_fops = {
    .read    = xxx_read,
};

2. 创建阻塞IO

DECLARE_WAIT_QUEUE_HEAD(xxx_waitQueueHead); // 定义及初始化等待队列头

ssize_t xxx_read(struct file *file, char __user *buf, size_t size, loff_t *offset)
{
    unsigned char ret;

    if(file->f_flags & O_NONBLOCK)
    {
        // 非阻塞IO模式
    }
    else
    {
        // 阻塞IO模式
        DECLARE_WAITQUEUE(wq, current);            // 创建等待队列
        add_wait_queue(&xxx_waitQueueHead, &wq);   // 将 等待队列 加入 等待队列头
        set_current_state(TASK_INTERRUPTIBLE);
        schedule();                                // 睡眠,等待唤醒

        remove_wait_queue(&xxx_waitQueueHead, &wq);// 唤醒后,从 等待队列头 删除 等待队列
    }

    ......

    // 将内核空间kernel_buffer复制到用户空间buf
    ret = copy_to_user(buf, &kernel_buffer, size); 

    return 0;
}

3. 唤醒

唤醒步骤一般在中断处理函数或下半部函数中调用

wake_up(&xxx_waitQueueHead);

4. 编写应用程序

int main(int argc, char **argv)
{
    int fd;
    char status;

    fd = open("/dev/xxxDev", O_RDWR); // 默认以阻塞IO模式打开

    while(1) {
        read(fd, &status, 1); // 调用kernel xxx_read()
        printf("read: %d\n", status);
    }

    close(fd);
    return 0;
}

非阻塞IO

1. 创建 struct file_operations 变量

const struct file_operations xxx_fops = {
    .poll    = xxx_poll,
};

2. 创建非阻塞IO

DECLARE_WAIT_QUEUE_HEAD(xxx_waitQueueHead); // 定义及初始化等待队列头

unsigned int xxx_poll(struct file *file, struct poll_table_struct *wait)
{
    poll_wait(file, &xxx_waitQueueHead, wait); // 睡眠,等待唤醒

    return xxx_val? POLLIN : 0;
}

3. 唤醒

唤醒步骤一般在中断处理函数或下半部函数中调用

wake_up(&xxx_waitQueueHead);

4. 编写应用程序

  • SELECT_METHOD

    #include <sys/select.h>
    
    int main(int argc, char **argv)
    {
        fd_set readfds;
        int nfds;
        struct timeval timeout;
        int fd, ret;
        char status;
    
        fd = open("/dev/xxxDev", O_RDWR | O_NONBLOCK); // 以非阻塞IO模式打开
    
        while(1) {
            FD_ZERO(&readfds);   // 置零读文件描述符
            FD_SET(fd, &readfds);// 将fd加入读文件描述符
            nfds = fd + 1;       // 设置读文件描述符的个数
    
            timeout.tv_sec = 3; // 3秒超时
            timeout.tv_usec = 0;
    
            /*
             * 调用kernel xxx_poll()
             * 如果3秒内,有数据可读,调用read()
             * 如果3秒内,没有数据可读,返回超时状态
             */
            ret = select(nfds, &readfds, NULL, NULL, &timeout); 
            if(ret > 0)
            {
                if(FD_ISSET(fd, &readfds)) {
                    read(fd, &status, 1); // 调用kernel xxx_read()
                    printf("read: %d\n", status);
                }
                else {
                    printf("no this fd!\n");
                }
            }
            else if(ret == 0)
            {
                printf("timeout!\n");
            }
            else
            {
                printf("error!\n");
            }
        }
    
        close(fd);
        return 0;
    }
  • POLL_METHOD

    #include <poll.h>
    
    int main(int argc, char **argv)
    {
        struct pollfd fds;
        nfds_t nfds;
        int timeout;
        int fd, ret;
        char status;
    
        fd = open("/dev/xxxDev", O_RDWR | O_NONBLOCK); // 以非阻塞IO模式打开
    
        fds.fd = fd;
        fds.events = POLLIN; // 监听POLLIN事件
        nfds  = 1;
    
        timeout = 500;       // 500ms超时
    
        while(1) {
            /*
             * 调用kernel xxx_poll()
             * 如果500ms内,有数据可读,调用read()
             * 如果500ms内,没有数据可读,返回超时状态
             */
            ret = poll(&fds, nfds, timeout);
            if(ret > 0)
            {
                read(fd, &status, 1); // 调用kernel xxx_read()
                printf("read: %d\n", status);
            }
            else if(ret == 0)
            {
                printf("timeout!\n");
            }
            else
            {
                printf("error!\n");
            }
        }
    
        close(fd);
        return 0;
    }

异步通知

1. 创建 struct file_operations 变量

const struct file_operations xxx_fops = {
    .fasync  = xxx_fasync,
};

2. 创建异步通知

struct fasync_struct *fasync_queue; // 定义异步通知

int xxx_fasync(int fd, struct file *file, int on)
{
    return fasync_helper(fd, file, on, &fasync_queue); // 初始化异步通知
}

3. 唤醒

唤醒步骤一般在中断处理函数或下半部函数中调用

kill_fasync(&fasync_queue, SIGIO, POLL_IN); // 向应用程序发送SIGIO信号

4. 编写应用程序

#include <signal.h>

int fd;

void xxx_sighandler(int num)
{
    char status;

    read(fd, &status, 1); // 调用kernel xxx_read()
    printf("read: %d\n", status);
}

int main()
{
    fd = open("/dev/xxxDev", O_RDWR | O_NONBLOCK); // 以非阻塞IO模式打开

    fcntl(fd, F_SETOWN, getpid()); // 将当前进程的进程号告诉给内核

    // 设置异步通知模式,调用kernel xxx_fasync()
    fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | FASYNC); 

    /*
     * 设置SIGIO信号的处理函数为xxx_sighandler()
     *
     * 当kernel调用kill_fasync()向应用程序发送SIGIO信号时,
     * 应用程序调用xxx_sighandler()
     */
    signal(SIGIO, xxx_sighandler);

    while(1);
    close(fd);
    return 0;
}
PreviousIRQ_driverNextlinux_own_driver

Last updated 4 years ago

Was this helpful?