P18: 在VT100终端上反白显示
printf("\033[7more?\033[m");
P21: 打开键盘,读取键盘输入。无论输入是标准输入还是被重定向到其他文件,都从键盘接受按键输入。
FILE * fp_tty;
fp_tty=fopen("/dev/tty","r");
while((c=getc(fp_tty)!=EOF)
{
if(c=='q')
......
}
P29: 已登录用户的信息是放在/var/adm/utmp中,数据结构包含在
中
P33: man -k keyword 查找带有“keyword”的联机文档. 在其中进一步查找含有read的文档的方法是 man -k keyword | grep read
P58: 处理系统调用中的错误
内核通过全局变量errno来记录当前系统调用的错误代码。错误代码定义在中,可以直接调用perror()来打印对应的系统出错信息.
处理errno 的例子
#include
extern int errno;
....
int fd = open("file",O_RDONLY);
if(fd == -1)
{
if(errno == ENOENT)
printf("There is no such file\n");
else if(errno == EINTR)
.....
}
而使用perror的例子
int fd = open("file",O_RDONLY);
if(fd == -1)
{
perror("Can not open file");
}
P68: 目录操作有关函数 opendir(), readdir_r(),telldir(),seekdir(), rewinddir(), closedir()
P73: 获取文件信息的系统调用 state()
P157:终端模式小结:
1 规范模式。驱动程序输入的字符保存在缓冲区,并且仅在接受到回车键时才将这些缓冲的字符发送到程序。
2 非规范模式。当缓冲和编辑被关闭是,连接被称为处于非规范模式。
3 raw 模式。每个处理步骤被当作一个独立的为控制。
可以用stty 命令来设置终端的状态。
stty -icanon; 关闭规范模式,输入直接被驱动程序发送到程序
或者在程序中调用
set_crmode()
{
struct termios ttystate;
tcgetattr(0,&ttystate); // read curr. setting
ttystate.c_lflag &= ~ICANON; // no buffer
ttystate.c_cc[VMIN] = 1; // read one char at a time
tcsetattr(0, TCSANOW, &ttystate); // install setting
}
P163: 阻塞与非阻塞输入。 阻塞不仅仅是终端链接的特性,而是任何一个打开的文件的属性。程序可以使用fcntl或者open吧文件描述符启动为非阻塞(noneblick input)。如果文件描述符设置了O_NDELAY位,并且那块空间是空的,read调用返回0.
set_nodelay_mode()
{
int termflags;
termflags |= O_NODELAY;
fcntl(0,F_SETEL,termflags); // 把标准输入设置成none delay mode
}
P203: 信号处理 sigaction
PISIX标准。
int sigaction(signalnumber, action, prevaction);
struct sigaction{
void (* sa_handler)(); /* SIG_DFL, SIG_IGN, or function */
void (* sa_sigaction)(int, siginfo_t *, void *); /* new handler */
sigset_t sa_mask; /* signals to block while handling */
int sa_flags; /* enable various behaviors */
}
sa_flags :
SA_RESETHAND 当处理函数被调用时重置信号的处理函数为系统默认处理函数,也就是采用捕鼠器模式
SA_NODEFER 在处理信号时关闭信号的自动阻塞。这样允许递归调用。
SA_RESTART 当系统调用是针对一些慢速的设备或类似的系统调用,重新开始,而不是返回。采用BSD模式
SA_SIGINFO 位被设置上的时候, 内核使用sa_handler作为信号的处理函数. sa_handler 是类似于signal()的处理方法,只能获得捕获信号的编号. 如果该位没有被置上,则使用sa_sigaction做为信号的处理函数,在这种情况下内核传递给函数的不仅是信号编号,还包括了指向描述信号产生原因和条件的结构体.
在Fedora7上测试,发现无论 SA_SIGINFO是否被设置,只要sa_sigaction被连接上,都会执行sa_sigaction指定的函数。
如果希望在调用系统的默认处理函数之前做点什么事情,可以使用SA_RESETHAND注册一个函数,在改函数中完成你所希望的事情,然后再重新发送这个信号。
测试代码如下
#include
#include
#define INPUTLEN 100
main()
{
struct sigaction newhandler;
sigset_t blocked;
void inthandler();
void intsignalaction(int s, siginfo_t * pinof, void * p);
char x[INPUTLEN];
char readback=0;
printf("1 to use sa_handler\n2 to use sa_sigaction(default)\nyou input:");
readback = getchar();
if(readback == '1')
{
printf("use SA_RESETHAND | SA_RESTART\n");
newhandler.sa_flags = SA_RESETHAND | SA_RESTART;
}
else
{
printf("n = %x%c\n",readback,readback);
printf("use SA_RESETHAND | SA_RESTART | SA_SIGINFO\n");
newhandler.sa_flags = SA_RESETHAND | SA_RESTART | SA_SIGINFO;
}
/* load these two members first */
newhandler.sa_handler = inthandler;
// newhandler.sa_sigaction = intsignalaction;
sigemptyset(&blocked);
sigaddset(&blocked, SIGQUIT);
newhandler.sa_mask = blocked;
printf("newhandler.sa_flags=%x\n", newhandler.sa_flags);
if(sigaction(SIGINT, &newhandler, NULL) == -1)
perror("sigaction");
else
while(1){
fgets(x, INPUTLEN, stdin);
printf("main loop input: %s",x);
}
}
void inthandler(int s)
{
printf("inthandler Called with signal %d\n",s);
sleep(s);
printf("done handling signal %d\n",s);
}
#if 0
siginfo_t {
int si_signo; /* Signal number */
int si_errno; /* An errno value */
int si_code; /* Signal code */
pid_t si_pid; /* Sending process ID */
uid_t si_uid; /* Real user ID of sending process */
int si_status; /* Exit value or signal */
clock_t si_utime; /* User time consumed */
clock_t si_stime; /* System time consumed */
sigval_t si_value; /* Signal value */
int si_int; /* POSIX.1b signal */
void * si_ptr; /* POSIX.1b signal */
void * si_addr; /* Memory location which caused fault */
int si_band; /* Band event */
int si_fd; /* File descriptor */
}
#endif
void siginfo_t_dump(siginfo_t * pinof)
{
printf("si_signo = %d\n", pinof->si_signo);
printf("si_errno = %d\n", pinof->si_errno);
/* printf("si_code = %d\n", pinof->si_code);
printf("si_pid = %d\n", pinof->si_pid);
printf("si_uid = %d\n", pinof->si_uid);
printf("si_status = %d\n", pinof->si_status);
printf("si_utime = %d\n", pinof->si_utime);
printf("si_stime = %d\n", pinof->si_stime);
printf("si_value = %d\n", pinof->si_value);
printf("si_int = %d\n", pinof->si_int);
printf("si_ptr = %d\n", pinof->si_ptr);
printf("si_addr = %d\n", pinof->si_addr);
printf("si_band = %d\n", pinof->si_band);
printf("si_fd = %d\n", pinof->si_fd);
*/
}
void intsignalaction(int s, siginfo_t * pinof, void * p)
{
printf("intsignalaction Called with signal %d\n",s);
// siginfo_t_dump(pinof);
sleep(2);
printf("done handling signal %d\n",s);
}
P218 使用异步IO
方法一 使用O_ASYNC
使用fcntl的F_SETOWN命令来告诉内核发送输入通知信号给进程
通过调用fcntl来设置文件描述符0的O_ASYNC位来打开输入信号。当有一个从键盘来的字符到达,内核向进程发送SIGIO信号. SIGIO的处理函数使用标准curses函数来读入这个字符。红色为相关代码。注意set_ticker()可能是从curser库里头拿掉了,需要自己实现
#include
#include
#include
#include
#include
#define MESSAGE "hello"
#define BLANK " "
int row = 10;
int col =0;
int dir = 1;
int delay = 200;
int done = 0;
main()
{
void on_alarm(int);
void on_input(int);
void enable_kdb_signals();
initscr();
crmode();
noecho();
clear();
signal(SIGIO,on_input);
enable_kdb_signals();
signal(SIGALRM, on_alarm);
set_ticker(delay);
move(row,col);
addstr(MESSAGE);
while(!done)
pause();
endwin();
}
void on_input(int signum)
{
int c = getch();
if(c== 'Q' || c==EOF)
done = 1;
else if(c==' ')
dir = -dir;
}
void on_alarm(int signum)
{
signal(SIGALRM, on_alarm);
mvaddstr(row, col, BLANK);
col+=dir;
mvaddstr(row, col, MESSAGE);
refresh();
if(dir == -1 && col <= 0)
dir = 1;
else if(dir == 1 && col + strlen(MESSAGE)>=COLS)
dir = -1;
}
void enable_kdb_signals()
{
int fd_flags;
fcntl(0, F_SETOWN, getpid());
fd_flags=fcntl(0, F_GETFL);
fcntl(0,F_SETFL,(fd_flags | O_ASYNC));
}
int set_ticker(int n_msecs)
{
struct itimerval new_timeset;
long n_sec,n_usecs;
n_sec = n_msecs/1000;
n_usecs=(n_msecs%1000)*1000L;
new_timeset.it_interval.tv_sec=n_sec;
new_timeset.it_interval.tv_usec=n_usecs;
new_timeset.it_value.tv_sec = n_sec;
new_timeset.it_value.tv_usec= n_usecs;
return setitimer(ITIMER_REAL,&new_timeset,NULL);
}
P221 方法二 使用aio_read
1. 设置输入被读入时候的处理函数on_input
2. 设置 kbcbuf中的变量来指明等待什么类型的输入,当输入是产生什么信号。这里在读取按键输入的时候产生一个SIGIO信号,我们在注册了SIGIO信号的处理函数以后把在处理函数中读取kbcbuf中的数据.
3. aio_read不会阻塞程序,而是在完成以后给系统发信号。
注意1. aio_read 在librt里头,需要在编译是指定。 2. 通过实践,似乎这种方法的响应速度比较慢(个人感觉)
如下是代码,相关代码为红色
//bounce_aio.c
#include
#include
#include
#include
#include
#include
#define MESSAGE "hello"
#define BLANK " "
int row = 10;
int col =0;
int dir = 1;
int delay = 200;
int done = 0;
static struct aiocb kbcbuf;
main()
{
void on_alarm(int);
void on_input(int);
void setup_aio_buffer();
initscr();
crmode();
noecho();
clear();
signal(SIGIO,on_input);
setup_aio_buffer();
aio_read(&kbcbuf);// request for the first round read key
signal(SIGALRM, on_alarm);
set_ticker(delay);
move(row,col);
addstr(MESSAGE);
while(!done)
pause();
endwin();
}
void on_input(int signum)
{
int c;
char * cp = (char *)kbcbuf.aio_buf;
if(aio_error(&kbcbuf)!=0)
perror("reading failed!");
else
if(aio_return(&kbcbuf) == 1)
{
c = *cp;
if(c=='Q' || c=='q' || c == EOF)
done = 1;
else if(c == ' ')
dir = -dir;
}
aio_read(&kbcbuf); //request for next round read key board
}
void on_alarm(int signum)
{
signal(SIGALRM, on_alarm);
mvaddstr(row, col, BLANK);
col+=dir;
mvaddstr(row, col, MESSAGE);
refresh();
if(dir == -1 && col <= 0)
dir = 1;
else if(dir == 1 && col + strlen(MESSAGE)>=COLS)
dir = -1;
}
void setup_aio_buffer()
{
static char input[1];
kbcbuf.aio_fildes=0;
kbcbuf.aio_buf = input;
kbcbuf.aio_nbytes = 1;
kbcbuf.aio_offset = 0;
kbcbuf.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
kbcbuf.aio_sigevent.sigev_signo = SIGIO; /* SEND SIGIO */
}
int set_ticker(int n_msecs)
{
struct itimerval new_timeset;
long n_sec,n_usecs;
n_sec = n_msecs/1000;
n_usecs=(n_msecs%1000)*1000L;
new_timeset.it_interval.tv_sec=n_sec;
new_timeset.it_interval.tv_usec=n_usecs;
new_timeset.it_value.tv_sec = n_sec;
new_timeset.it_value.tv_usec= n_usecs;
return setitimer(ITIMER_REAL,&new_timeset,NULL);
}
P285 在C程序中读取环境变量
#include
char * cp = getevn("LANG")
阅读(1275) | 评论(0) | 转发(0) |