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);
#include
int 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;
}
===============================================================================
![]()