Linux 中直接的 I/O 端口读写
记录锁定
非阻塞 I/O
I/O 多工
异步 I/O
内存映射
=============================================================================== #include <unistd.h> /* for libc5 */ #include <sys/io.h> /* for glibc */ int ioperm (unsigned long from, unsigned long num, int turn_on); int iopl (int level); ------------------------------------------------------------------------------- EXAMPLE: /* get PC speak I/O ports access permission and implement a beep function */ #define COUNTER_ADDR 0x61 int beepCount = 500000; BOOL InitIOPerm () { if (ioperm (COUNTER_ADDR, 1, TRUE)) { fprintf (stderr, "Can not get beep I/O permission!\n"); return FALSE; } return TRUE; } void CleanupIOPerm () { ioperm (COUNTER_ADDR, 1, FALSE); } void GUIAPI Beep (void) { outb (inb (COUNTER_ADDR) | 3, COUNTER_ADDR); usleep (beepCount); outb (inb (COUNTER_ADDR) & 0xFC, COUNTER_ADDR); } ===============================================================================
=============================================================================== #include <sys/time.h> #include <sys/types.h> #include <unistd.h> int select (int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); FD_CLR (int fd, fd_set *set); FD_ISSET (int fd, fd_set *set); FD_SET (int fd, fd_set *set); FD_ZERO (fd_set *set); #includeint poll(struct pollfd *ufds, unsigned int nfds, int timeout); ------------------------------------------------------------------------------- struct pollfd { int fd; /* file descriptor */ short events; /* requested events */ short revents; /* returned events */ }; ------------------------------------------------------------------------------- * select 中的 n 是所等待文件描述符中最大的值加 1. ------------------------------------------------------------------------------- EXAMPLE 1: /* 在 Virtual Console on MiniGUI 中, 我们用 poll 等待主伪终端上的数据 */ void ReadMasterPty (PCONINFO con) { BYTE buff [BUFSIZ + 1]; int nRead; struct pollfd fd = {con->masterPty, POLLIN, 0}; int ret; ret = poll (&fd, 1, 10); // about 0.01s if (ret == 0) { return; } else if (ret > 0) { if ((nRead = read (con->masterPty, buff, BUFSIZ)) > 0) { VtWrite (con, buff, nRead); TextRefresh (con, true); } } } /* 如果没有数据, 我们处理 MiniGUI 的消息, 包括键盘和鼠标事件 */ ... // Enter message loop. do { // It is time to read from master pty, and output. ReadMasterPty (pConInfo); if (pConInfo->terminate) break; while (HavePendingMessage (hMainWnd)) { if (!GetMessage (&Msg, hMainWnd)) break; DispatchMessage (&Msg); } } while (TRUE); ... /* 我们也可以用非阻塞 I/O 实现 ReadMasterPty, 但这种方法非常消耗 CPU 资源 */ ------------------------------------------------------------------------------- EXAMPLE 1: /* SVGALib 用 select 函数实现 vga_waitevent 函数等待键盘和鼠标事件 */ int vga_waitevent(int which, fd_set * in, fd_set * out, fd_set * except, struct timeval *timeout) { fd_set infdset; int fd, retval; if (!in) { in = &infdset; FD_ZERO(in); } fd = __svgalib_mouse_fd; /* __svgalib_mouse_fd might change on vc switch!! */ if ((which & VGA_MOUSEEVENT) && (fd >= 0)) FD_SET(fd, in); if (which & VGA_KEYEVENT) { fd = __svgalib_kbd_fd; if (fd >= 0) { /* we are in raw mode */ FD_SET(fd, in); } else { FD_SET(__svgalib_tty_fd, in); } } if (select(FD_SETSIZE, in, out, except, timeout) < 0) return -1; retval = 0; fd = __svgalib_mouse_fd; if ((which & VGA_MOUSEEVENT) && (fd >= 0)) { if (FD_ISSET(fd, in)) { retval |= VGA_MOUSEEVENT; FD_CLR(fd, in); mouse_update(); } } if (which & VGA_KEYEVENT) { fd = __svgalib_kbd_fd; if (fd >= 0) { /* we are in raw mode */ if (FD_ISSET(fd, in)) { FD_CLR(fd, in); retval |= VGA_KEYEVENT; keyboard_update(); } } else if (FD_ISSET(__svgalib_tty_fd, in)) { FD_CLR(__svgalib_tty_fd, in); retval |= VGA_KEYEVENT; } } return retval; } ===============================================================================
=============================================================================== #include <unistd.h> #include <sys/mman.h> #ifdef _POSIX_MAPPED_FILES void* mmap (void *start, size_t length, int prot, int flags, int fd, off_t offset); int munmap (void *start, size_t length); #endif ------------------------------------------------------------------------------- * mmap 的 start 一般设为 0, 由系统决定选择什么地址作为起始的映射地址. * prot 的取值必须和 fd 的打开标志一直. * 写时复制的含义. ------------------------------------------------------------------------------- SAMPLE: /* 打开一个文件, 利用 mmap 将文件反序保存 为简单起见, 只处理文件的前 10 个字符 */ #include <stdio.h> #include <unistd.h> #include <sys/mman.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int main (int args, char* arg[]) { int i; int fd; char* mem; if ((fd = open ("temp", O_RDWR)) < 0) { perror ("open error"); return -1; } mem = mmap (0, 10, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd, 0); if (mem == MAP_FAILED) { perror ("mmap error:"); return 1; } for (i = 0; i < 5; i++) { char temp; temp = mem [i]; mem [i] = mem [9 - i]; mem [9 - i] = temp; } munmap (mem, 10); close (fd); return 0; } ===============================================================================