程序清单 14-1 长的非堵塞write
/**
* 程序清单 14-1 长的非堵塞write P357
*
* zy:
* 可以运行,和书上类似。
*/
#include "apue.h"
#include "error.c"
#include <fcntl.h>
#include <errno.h> //定义了通过错误码来回报错误资讯的宏
//宏定义为一个int型态的左值, 包含任何函式使用errno功能所产生的上一个错误码
#include <fcntl.h> //file control
char buf[500000];
void set_fl(int fd,int flags){//flags就是要准备打开的标志
int val;
if((val= fcntl(fd,F_GETFL,0))<0){
err_sys("fcntl F_GETFL error");
}
val |=flags; //与标志表示打开一个
if(fcntl(fd,F_SETFL,val)<0){
err_sys("fcntl F_SETFL error");
}
}
void clr_fl(int fd,int flags){//flags就是要关闭的标志
int val;
if((val= fcntl(fd,F_GETFL,0))<0){
err_sys("fcntl F_GETFL error");
}
val &=~flags; //将这个标志关闭
if(fcntl(fd,F_SETFL,val)<0){
err_sys("fcntl F_SETFL error");
}
}
int main(void){
int ntowrite,nwrite;
char *ptr;
ntowrite=read(STDIN_FILENO,buf,sizeof(buf)); //STDIN_FILENO: Standard file descriptors 文件标识符
fprintf(stderr,"read %d bytes\n",ntowrite); //stderr:Standard streams 应该是以流的形式
set_fl(STDOUT_FILENO,O_NONBLOCK);
ptr=buf;
while(ntowrite>0){
errno=0;
nwrite=write(STDOUT_FILENO,ptr,ntowrite);
fprintf(stderr,"nwrite = %d , errno = %d \n",nwrite,errno);
if(nwrite>0){
ptr+=nwrite;
ntowrite-=nwrite;
}
}
clr_fl(STDOUT_FILENO,O_NONBLOCK);
exit(0);
}
程序清单 14-2 加锁和解锁一个文件区域的函数
/**
* 程序清单 14-2 加锁和解锁一个文件区域的函数
* zy:
* 有了这几个函数就可以使用下面的宏定义了。
#define read_lock(fd, offset, whence, len) \
lock_reg((fd), F_SETLK, F_RDLCK, (offset), (whence), (len))
#define readw_lock(fd, offset, whence, len) \
lock_reg((fd), F_SETLKW, F_RDLCK, (offset), (whence), (len))
#define write_lock(fd, offset, whence, len) \
lock_reg((fd), F_SETLK, F_WRLCK, (offset), (whence), (len))
#define writew_lock(fd, offset, whence, len) \
lock_reg((fd), F_SETLKW, F_WRLCK, (offset), (whence), (len))
#define un_lock(fd, offset, whence, len) \
lock_reg((fd), F_SETLK, F_UNLCK, (offset), (whence), (len))
*/
#include "apue.h"
#include "error.c"
#include <fcntl.h>
int lock_reg(int fd,int cmd, int type,off_t offset,int whence,off_t len){
struct flock lock;
lock.l_type=type;
lock.l_start=offset;
lock.l_whence=whence;
lock.l_len=len;
return (fcntl(fd,cmd,&lock));
}
程序清单 14-3 测试一个文件的锁的状态的函数
/**
* 程序清单 14-3 测试一个文件的锁的状态的函数 P362
* zy:
* 可以使用下面的宏了
#define is_read_lockable(fd, offset, whence, len) \
(lock_test((fd), F_RDLCK, (offset), (whence), (len)) == 0)
#define is_write_lockable(fd, offset, whence, len) \
(lock_test((fd), F_WRLCK, (offset), (whence), (len)) == 0)
*/
#include "apue.h"
#include "error.c"
#include <fcntl.h>
pid_t lock_test(int fd,int type,off_t offset,int whence,off_t len){
struct flock lock;
lock.l_type = type;
lock.l_start = offset;
lock.l_whence=whence;
lock.l_len=len;
if(fcntl(fd,F_GETLK,&lock)<0){
err_sys("fcntl error");
}
if(lock.l_type==F_ULOCK){//没锁的话
return 0;
}
return (lock.l_pid); //有锁的话返回pid
}
程序清单 14-4 死锁检测实例
/**
* 程序清单 14-4 死锁检测实例 P362
* zy:
* 很神奇
* 我完全没看出这个tell_wait机制有作用,所以我把其注释了
* 注释了之后代码还是正常运行,所以我认为tell_wait在这里是没用的
* 而是系统自己的机制完成了释放另一个进程的拿到的锁的过程
asd@asd-desktop:~/workspace/test/src$ ./a.out
parent:got the lock, byte 1
child:got the lock, byte 0
child,writew_lock error: Resource deadlock avoided
parent:got the lock, byte 0
asd@asd-desktop:~/workspace/test/src$
*
*/
#include "apue.h"
#include "error.c"
#include <fcntl.h>
#include <fcntl.h>
int lock_reg(int fd,int cmd, int type,off_t offset,int whence,off_t len){
struct flock lock;
lock.l_type=type;
lock.l_start=offset;
lock.l_whence=whence;
lock.l_len=len;
return (fcntl(fd,cmd,&lock));
}
static void lockabyte(const char *name,int fd, off_t offset){
if(writew_lock(fd,offset,SEEK_SET,1)<0){
err_sys("%s,writew_lock error",name);
}
printf("%s:got the lock, byte %ld\n",name,offset);
}
int main(void){
int fd;
pid_t pid;
if((fd=creat("templock",FILE_MODE))<0){
err_sys("creat error");
}if(write(fd,"ab",2)!=2){
err_sys("write error");
}
//TELL_WAIT();
if((pid=fork())<0){
err_sys("fork error");
}else if(pid==0){
lockabyte("child",fd,0);
//TELL_PARENT(getppid());
//WAIT_PARENT();
lockabyte("child",fd,1);
}else{
lockabyte("parent",fd,1);
//TELL_CHILD(pid);
//WAIT_CHILD();
lockabyte("parent",fd,0);
}
exit(0);
}
程序清单 14-5 在文件的整体上加锁
/**
* 程序清单 14-5 在文件的整体上加锁 P365
* zy:
* 这里是完成在13-2中的一个函数,
* 也就是守护进程对文件加锁
*
*/
#include <unistd.h>
#include <fcntl.h>
int lockfile(int fd){
struct flock fl;
fl.l_type=F_WRLCK;
fl.l_start=0;
fl.l_whence=SEEK_SET;
fl.l_len=0;
return (fcntl(fd,F_SETLK,&fl));
}
程序清单 14-6 确定是否支持强制性锁机制
/**
* 程序清单 14-6 确定是否支持强制性锁机制 P369
* zy:
* 看样子我的机子是支持强制性锁
* 运行结果:
asd@asd-desktop:~/workspace/test/src$ ./a.out temp.lock
读锁试图锁上已经被父进程加了写锁的区域得到的错误代码:11
read Ok 强制性锁没有其作用,buf=ab
asd@asd-desktop:~/workspace/test/src$
*
*/
#include "apue.h"
#include "error.c"
#include <errno.h>
#include <fcntl.h>
#include <sys/wait.h>
void set_fl(int fd,int flags){//flags就是要准备打开的标志
int val;
if((val= fcntl(fd,F_GETFL,0))<0){
err_sys("fcntl F_GETFL error");
}
val |=flags; //与标志表示打开一个
if(fcntl(fd,F_SETFL,val)<0){
err_sys("fcntl F_SETFL error");
}
}
void clr_fl(int fd,int flags){//flags就是要关闭的标志
int val;
if((val= fcntl(fd,F_GETFL,0))<0){
err_sys("fcntl F_GETFL error");
}
val &=~flags; //将这个标志关闭
if(fcntl(fd,F_SETFL,val)<0){
err_sys("fcntl F_SETFL error");
}
}
int lock_reg(int fd,int cmd, int type,off_t offset,int whence,off_t len){
struct flock lock;
lock.l_type=type;
lock.l_start=offset;
lock.l_whence=whence;
lock.l_len=len;
return (fcntl(fd,cmd,&lock));
}
int main(int argc, char **argv) {
int fd;
pid_t pid;
char buf[5];
struct stat statbuf;
if(argc!=2){
fprintf(stderr,"usage:%s filename\n",argv[0]);
exit(1);
}
if((fd=open(argv[1],O_RDWR|O_CREAT|O_TRUNC,FILE_MODE))<0){
err_sys("open error");
}
if(write(fd,"abcdef",6)!=6){
err_sys("write error");
}
/*
* 开启强制性锁
*/
if(fstat(fd,&statbuf)<0){
err_sys("fstat error");
}
if(fchmod(fd,(statbuf.st_mode & ~S_IXGRP)|S_ISGID)<0){
err_sys("fchomd error");
}
//TELL_WAIT();
if((pid=fork())<0){
err_sys("fork error");
}else if( pid>0){
if(write_lock(fd,0,SEEK_CUR,0)<0){
err_sys("write lock error");
}
//TELL_CHILD(pid);
if(waitpid(pid,NULL,0)<0){
err_sys("waitpid error");
}
}else{
//WAIT_PARENT();
set_fl(fd,O_NONBLOCK);
/**
* 我们先上上锁,看看能得到什么
*/
if(read_lock(fd,0,SEEK_SET,0)!=-1){
err_sys("child:read_lock succeeded");
}
printf("读锁试图锁上已经被父进程加了写锁的区域得到的错误代码:%d\n",errno);
/**
* 但是我们还是试图去读
*/
if(lseek(fd,0,SEEK_SET)==-1){
err_sys("lseek error");
}
if(read(fd,buf,2)<0){
err_ret("read failed ,因为强制性锁在起作用\n");
}else{
printf("read Ok 强制性锁没有其作用,buf=%2.2s\n",buf);
}
}
exit(0);
}
程序清单 14-7 检查描述符是否引用STREAMS设备
程序清单 14-8 测试isastream函数
/**
* 程序清单 14-7 检查描述符是否引用STREAMS设备 P373
* 程序清单 14-8 测试isastream函数 P373
*
* zy:
* I_CANPPU试图改变属性,如果能改,则是一个stream
*
* 运行结果:
asd@asd-desktop:~/workspace/test/src$ ./a.out /dev/tty /dev/fd /dev/null /etc/motd
/dev/tty not a stream: Invalid argument
/dev/fd not a stream: Inappropriate ioctl for device
/dev/null not a stream: Inappropriate ioctl for device
/etc/motd not a stream: Inappropriate ioctl for device
asd@asd-desktop:~/workspace/test/src$
*/
#include <stropts.h> //stropts.h - STREAMS interface
#include <unistd.h>
#include "apue.h"
#include <fcntl.h>
#include "error.c"
int isastream(int fd){
return (ioctl(fd,I_CANPUT,0)!=-1);
}
int main(int argc, char **argv) {
int i,fd;
for(i=1;i<argc;i++){
if((fd=open(argv[i],O_RDONLY))<0){
err_ret("%s can't open",argv[i]);
continue;
}
if(isastream(fd)==0){
err_ret("%s not a stream",argv[i]);
}else{
err_msg("%s:stream device",argv[i]);
}
}
}
程序清单 14-9 列表留中的模块名
/**
* 程序清单 14-9 列表留中的模块名 P375
* zy:
* 运行结果:
asd@asd-desktop:~/workspace/test/src$ who
asd tty7 2014-03-20 09:13
asd pts/0 2014-03-20 10:55 (:0.0)
asd@asd-desktop:~/workspace/test/src$ sudo ./a.out /dev/console
/dev/console is not a stream
asd@asd-desktop:~/workspace/test/src$ sudo ./a.out /dev/pts/0
/dev/pts/0 is not a stream
asd@asd-desktop:~/workspace/test/src$
* 难道在我的机子上就不是一个STREAM设备?
*/
#include "apue.h"
#include <fcntl.h>
#include <stropts.h>
#include "error.c"
int main(int argc, char **argv) {
int fd,i,nmods;
struct str_list list;
if(argc!=2){
err_quit("usage:%s <pathname>",argv[0]);
}
if((fd=open(argv[1],O_RDONLY))<0){
err_sys("can't open %s",argv[1]);
}
if(isastream(fd)==0){
err_quit("%s is not a stream",argv[1]);
}
/*
* 看看有多少模块
*/
if((nmods=ioctl(fd,I_LIST,(void *)0))<0){
err_sys("I_LIST error for nmods");
}
printf("#modelues=%d\n",nmods);
/**
* 为模块名分配内存
*/
list.sl_modlist=calloc(nmods,sizeof(struct str_mlist));
if(list.sl_modlist==NULL){
err_sys("calloc error");
}
list.sl_nmods=nmods;
/**
* 拿到所有的名字
*/
if(ioctl(fd,I_LIST,&list)<0){
err_sys("I_LIST error for list");
}
/**
* 打印名字
*/
for(i=1;i<=nmods;i++){
printf("%s : %s\n",(i==nmods)?"driver":"module",list.sl_modlist++->l_name);
}
}
程序清单 14-10 用getmsg将标准输入复制到标准输出
/**
* 程序清单 14-10 用getmsg将标准输入复制到标准输出 P378
*
* zy:
* linux没有getmsg这个函数。不能运行
* 我自己man了一下没找到。
http://bbs.csdn.net/topics/360039652
*/
#include "apue.h"
#include <stropts.h>
#include "error.c"
#define BUFFSIZE 4096
int main(int argc, char **argv) {
int n,flag;
char ctlbuf[BUFFSIZE],datbuf[BUFFSIZE];
struct strbuf ctl,dat;
ctl.buf=ctlbuf;
ctl.maxlen=BUFFSIZE;
dat.buf=datbuf;
dat.maxlen=BUFFSIZE;
for(;;){
flag=0;
if((n=getmsg(STDIN_FILENO,&ctl,&dat,&flag))<0){
err_sys("getmsg error");
}
fprintf(stderr,"flag=%d,ctl.len=%d,dat.len=%d\n",flag,ctl.len,dat.len);
} if(dat.len==0){
exit(0);
} else if(dat.len>0){
if(write(STDOUT_FILENO,dat.buf,dat.len)!=dat.len)
err_sys("write error");
}
}
程序清单 14-11 readn和writen函数
/**
* 程序清单 14-11 readn和writen函数 P390
*
* zy:
* 读写指定量的数据,如果一次没有完成,那么会循环调用while来完成
*/
#include "apue.h"
ssize_t readn(int fd, void *ptr,size_t n){
size_t nleft;
ssize_t nread;
nleft=n;
while(nleft>0){
if((nread=read(fd,ptr,nleft))<0){
if(nleft==n){//这里是出错之后才会执行的语句
return(-1);
}else{
break;
}
}else if(nread==0){
break;
}
nleft-=nread;
ptr +=nread;
}
return (n-nleft);
}
ssize_t writen(int fd, void *ptr,size_t n){
size_t nleft;
ssize_t nwritten;
nleft=n;
while(nleft>0){
if((nwritten=write(fd,ptr,nleft))<0){
if(nleft==n){//这里是出错之后才会执行的语句
return(-1);
}else{
break;
}
}else if(nwritten==0){
break;
}
nleft-=nwritten;
ptr +=nwritten;
}
return (n-nleft);
}
程序清单 14-12 readn和writen函数
/**
* 程序清单 14-12 用储存映射I/O复制文件 P394
*
* zy:
* 用共享内存的方式完成了文件的复制
* 运行结果:
asd@asd-desktop:~/workspace/test/src$ gcc test2.c
asd@asd-desktop:~/workspace/test/src$ sudo ./a.out core core2
asd@asd-desktop:~/workspace/test/src$ ll core core2
-rw-r----- 1 asd asd 4677632 Mar 18 20:06 core
-rw-r--r-- 1 asd asd 4677632 Mar 20 12:40 core2
asd@asd-desktop:~/workspace/test/src$
*/
#include "apue.h"
#include <fcntl.h>
#include <sys/mman.h>
#include "error.c"
int main(int argc, char **argv) {
int fdin,fdout;
void *src,*dst;
struct stat statbuf;
if(argc!=3){
err_quit("usage: %s <from file> <to file>",argv[0]);
}
if((fdin=open(argv[1],O_RDONLY))<0){
err_sys("can't open %s for reading",argv[1]);
}
if((fdout=open(argv[2],O_RDWR|O_CREAT|O_TRUNC,FILE_MODE))<0){
err_sys("can't create %s for writing",argv[2]);
}
if(fstat(fdin,&statbuf)<0){/*为了拿到被复制文件的长度*/
err_sys("fstat error");
}
if(lseek(fdout,statbuf.st_size - 1,SEEK_SET)==-1){
err_sys("lseek error");
}
if(write(fdout,"",1)!=1){
err_sys("write error");
}
if((src=mmap(0,statbuf.st_size,PROT_READ,MAP_SHARED,fdin,0))==MAP_FAILED){
err_sys("mmap error for input");
}
if((dst=mmap(0,statbuf.st_size,PROT_READ|PROT_WRITE,MAP_SHARED,fdout,0))==MAP_FAILED){
err_sys("mmap error for output");
}
memcpy(dst,src,statbuf.st_size);
exit(0);
}