#include<sys/time.h>#include<stdlib.h>voidmaketimeout(struct timespec *tsp,long minutes){
struct timeval now;/* get the current time */gettimeofday(&now,NULL);
tsp->tv_sec = now.tv_sec;
tsp->tv_nsec = now.tv_usec *1000;/* usec to nsec *//* add the offset to get timeout value */
tsp->tv_sec += minutes *60;}//对于clock_gettime方法clock_gettime(CLOCK_REALTIME,&tout);
tmp =localtime(&tout.tv_sec);strftime(buf,sizeof(buf),"%r", tmp);printf("current time is %s\n", buf);
tout.tv_sec +=10;/* 10 seconds from now */
2. 关于sleep实现,采用sigsuspend函数实现
#include"apue.h"staticvoidsig_alrm(int signo){
/* nothing to do, just returning wakes up sigsuspend() */printf("cauth alarm\n");}unsignedintsleep3(unsignedint seconds){
struct sigaction newact, oldact;
sigset_t newmask, oldmask, suspmask;unsignedint unslept;/* set our handler, save previous information */
newact.sa_handler = sig_alrm;sigemptyset(&newact.sa_mask);
newact.sa_flags =0;sigaction(SIGALRM,&newact,&oldact);/* block SIGALRM and save current signal mask */sigemptyset(&newmask);sigaddset(&newmask, SIGALRM);sigprocmask(SIG_BLOCK,&newmask,&oldmask);alarm(seconds);
suspmask = oldmask;/* make sure SIGALRM isn't blocked */sigdelset(&suspmask, SIGALRM);/* wait for any signal to be caught */sigsuspend(&suspmask);/* some signal has been caught, SIGALRM is now blocked */
unslept =alarm(0);/* reset previous action */sigaction(SIGALRM,&oldact,NULL);/* reset signal mask, which unblocks SIGALRM */sigprocmask(SIG_SETMASK,&oldmask,NULL);return(unslept);}
#include<sys/wait.h>#include<errno.h>#include<signal.h>#include<unistd.h>intsystem(constchar*cmdstring)/* with appropriate signal handling */{
pid_t pid;int status;struct sigaction ignore, saveintr, savequit;
sigset_t chldmask, savemask;if(cmdstring ==NULL)return(1);/* always a command processor with UNIX */
ignore.sa_handler = SIG_IGN;/* ignore SIGINT and SIGQUIT */sigemptyset(&ignore.sa_mask);
ignore.sa_flags =0;if(sigaction(SIGINT,&ignore,&saveintr)<0)return(-1);if(sigaction(SIGQUIT,&ignore,&savequit)<0)return(-1);sigemptyset(&chldmask);/* now block SIGCHLD */sigaddset(&chldmask, SIGCHLD);if(sigprocmask(SIG_BLOCK,&chldmask,&savemask)<0)return(-1);if((pid =fork())<0){
status =-1;/* probably out of processes */}elseif(pid ==0){
/* child *//* restore previous signal actions & reset signal mask */sigaction(SIGINT,&saveintr,NULL);sigaction(SIGQUIT,&savequit,NULL);sigprocmask(SIG_SETMASK,&savemask,NULL);execl("/bin/sh","sh","-c", cmdstring,(char*)0);_exit(127);/* exec error */}else{
/* parent */while(waitpid(pid,&status,0)<0)if(errno != EINTR){
status =-1;/* error other than EINTR from waitpid() */break;}}/* restore previous signal actions & reset signal mask */if(sigaction(SIGINT,&saveintr,NULL)<0)return(-1);if(sigaction(SIGQUIT,&savequit,NULL)<0)return(-1);if(sigprocmask(SIG_SETMASK,&savemask,NULL)<0)return(-1);return(status);}
4. err_sys打印错误退出逻辑
staticvoiderr_doit(int errnoflag,int error,constchar*fmt, va_list ap){
char buf[MAXLINE];vsnprintf(buf, MAXLINE-1, fmt, ap);if(errnoflag)snprintf(buf+strlen(buf), MAXLINE-strlen(buf)-1,": %s",strerror(error));strcat(buf,"\n");fflush(stdout);/* in case stdout and stderr are the same */fputs(buf,stderr);fflush(NULL);/* flushes all stdio output streams */}/*
* Fatal error related to a system call.
* Print a message and terminate.
*/voiderr_sys(constchar*fmt,...){
va_list ap;va_start(ap, fmt);err_doit(1, errno, fmt, ap);va_end(ap);exit(1);}
5. 互斥量和条件变量的使用的使用
#include<pthread.h>struct msg {
struct msg *m_next;/* ... more stuff here ... */};struct msg *workq;
pthread_cond_t qready = PTHREAD_COND_INITIALIZER;
pthread_mutex_t qlock = PTHREAD_MUTEX_INITIALIZER;voidprocess_msg(void){
struct msg *mp;for(;;){
pthread_mutex_lock(&qlock);//一般都要加while, 担心因中断等异常返回;while(workq ==NULL)pthread_cond_wait(&qready,&qlock);
mp = workq;
workq = mp->m_next;pthread_mutex_unlock(&qlock);/* now process the message mp */}}voidenqueue_msg(struct msg *mp){
pthread_mutex_lock(&qlock);
mp->m_next = workq;
workq = mp;pthread_mutex_unlock(&qlock);pthread_cond_signal(&qready);}
#include"apue.h"#include<syslog.h>#include<fcntl.h>#include<sys/resource.h>voiddaemonize(constchar*cmd){
int i, fd0, fd1, fd2;
pid_t pid;struct rlimit rl;struct sigaction sa;/*
* Clear file creation mask.
*/umask(0);/*
* Get maximum number of file descriptors.
*/if(getrlimit(RLIMIT_NOFILE,&rl)<0)err_quit("%s: can't get file limit", cmd);/*
* Become a session leader to lose controlling TTY.
*/if((pid =fork())<0)err_quit("%s: can't fork", cmd);elseif(pid !=0)/* parent */exit(0);setsid();/*
* Ensure future opens won't allocate controlling TTYs.
*/
sa.sa_handler = SIG_IGN;sigemptyset(&sa.sa_mask);
sa.sa_flags =0;if(sigaction(SIGHUP,&sa,NULL)<0)err_quit("%s: can't ignore SIGHUP", cmd);if((pid =fork())<0)err_quit("%s: can't fork", cmd);elseif(pid !=0)/* parent */exit(0);/*
* Change the current working directory to the root so
* we won't prevent file systems from being unmounted.
*/if(chdir("/")<0)err_quit("%s: can't change directory to /", cmd);/*
* Close all open file descriptors.
*/if(rl.rlim_max == RLIM_INFINITY)
rl.rlim_max =1024;for(i =0; i < rl.rlim_max; i++)close(i);/*
* Attach file descriptors 0, 1, and 2 to /dev/null.
*/
fd0 =open("/dev/null", O_RDWR);
fd1 =dup(0);
fd2 =dup(0);/*
* Initialize the log file.
*/openlog(cmd, LOG_CONS, LOG_DAEMON);if(fd0 !=0|| fd1 !=1|| fd2 !=2){
syslog(LOG_ERR,"unexpected file descriptors %d %d %d",
fd0, fd1, fd2);exit(1);}}
8. 一个基本的后台模板
#include"apue.h"#include<syslog.h>#include<errno.h>externintlockfile(int);externintalready_running(void);voidreread(void){
/* ... */syslog(LOG_INFO,"re read config file\n");}voidsigterm(int signo){
syslog(LOG_INFO,"got SIGTERM; exiting");exit(0);}voidsighup(int signo){
syslog(LOG_INFO,"Re-reading configuration file");reread();}intmain(int argc,char*argv[]){
char*cmd;struct sigaction sa;int i;if((cmd =strrchr(argv[0],'/'))==NULL)
cmd = argv[0];else
cmd++;/*
* Become a daemon.
*/daemonize(cmd);/*
* Make sure only one copy of the daemon is running.
*/if(already_running()){
syslog(LOG_ERR,"daemon already running");exit(1);}/*
* Handle signals of interest.
*/
sa.sa_handler = sigterm;sigemptyset(&sa.sa_mask);sigaddset(&sa.sa_mask, SIGHUP);
sa.sa_flags =0;if(sigaction(SIGTERM,&sa,NULL)<0){
syslog(LOG_ERR,"can't catch SIGTERM: %s",strerror(errno));exit(1);}
sa.sa_handler = sighup;sigemptyset(&sa.sa_mask);sigaddset(&sa.sa_mask, SIGTERM);
sa.sa_flags =0;if(sigaction(SIGHUP,&sa,NULL)<0){
syslog(LOG_ERR,"can't catch SIGHUP: %s",strerror(errno));exit(1);}/*
* Proceed with the rest of the daemon.
*/for(i =0; i <10;++i){
syslog(LOG_INFO,"sleep %d\n", i);sleep(20);}exit(0);}
8. fnctl设置或清空文件描述的状态
#include"apue.h"#include<fcntl.h>voidset_fl(int fd,int flags)/* flags are file status flags to turn on */{
int val;if((val =fcntl(fd, F_GETFL,0))<0)err_sys("fcntl F_GETFL error");
val |= flags;/* turn on flags */if(fcntl(fd, F_SETFL, val)<0)err_sys("fcntl F_SETFL error");}#include"apue.h"#include<fcntl.h>voidclr_fl(int fd,int flags)/* flags are the file status flags to turn off */{
int val;if((val =fcntl(fd, F_GETFL,0))<0)err_sys("fcntl F_GETFL error");
val &=~flags;/* turn flags off */if(fcntl(fd, F_SETFL, val)<0)err_sys("fcntl F_SETFL error");}
#include"apue.h"staticvolatile sig_atomic_t sigflag;/* set nonzero by sig handler */static sigset_t newmask, oldmask, zeromask;staticvoidsig_usr(int signo)/* one signal handler for SIGUSR1 and SIGUSR2 */{
sigflag =1;}voidTELL_WAIT(void){
if(signal(SIGUSR1, sig_usr)== SIG_ERR)err_sys("signal(SIGUSR1) error");if(signal(SIGUSR2, sig_usr)== SIG_ERR)err_sys("signal(SIGUSR2) error");sigemptyset(&zeromask);sigemptyset(&newmask);sigaddset(&newmask, SIGUSR1);sigaddset(&newmask, SIGUSR2);/* Block SIGUSR1 and SIGUSR2, and save current signal mask */if(sigprocmask(SIG_BLOCK,&newmask,&oldmask)<0)err_sys("SIG_BLOCK error");}voidTELL_PARENT(pid_t pid){
kill(pid, SIGUSR2);/* tell parent we're done */}voidWAIT_PARENT(void){
while(sigflag ==0)sigsuspend(&zeromask);/* and wait for parent */
sigflag =0;/* Reset signal mask to original value */if(sigprocmask(SIG_SETMASK,&oldmask,NULL)<0)err_sys("SIG_SETMASK error");}voidTELL_CHILD(pid_t pid){
kill(pid, SIGUSR1);/* tell child we're done */}voidWAIT_CHILD(void){
while(sigflag ==0)sigsuspend(&zeromask);/* and wait for child */
sigflag =0;/* Reset signal mask to original value */if(sigprocmask(SIG_SETMASK,&oldmask,NULL)<0)err_sys("SIG_SETMASK error");}