Chinaunix首页 | 论坛 | 博客
  • 博客访问: 532655
  • 博文数量: 150
  • 博客积分: 5010
  • 博客等级: 大校
  • 技术积分: 1861
  • 用 户 组: 普通用户
  • 注册时间: 2008-03-17 00:19
文章分类

全部博文(150)

文章存档

2011年(1)

2009年(14)

2008年(135)

我的朋友

分类: LINUX

2008-11-13 10:46:54

#include    <sys/types.h>
#include    <sys/stat.h>
#include    <fcntl.h>
#include    "ourhdr.h"
#include    <errno.h>        /* for definition of errno */
#include    <stdarg.h>        /* ANSI C header file */
#include    "ourhdr.h"
#include <signal.h>

#include    <sys/types.h>    /* required for some of our prototypes */
#include    <stdio.h>        /* for convenience */
#include    <stdlib.h>        /* for convenience */
#include    <string.h>        /* for convenience */
#include    <unistd.h>        /* for convenience */
static void    err_doit(int, const char *, va_list);

#define    MAXLINE    4096            /* max line length */

#define    FILE_MODE    (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
                    /* default file access permissions for new files */
#define    DIR_MODE    (FILE_MODE | S_IXUSR | S_IXGRP | S_IXOTH)
                    /* default permissions for new directories */

//typedef    void    Sigfunc(int);    /* for signal handlers */


                    /* 4.3BSD Reno doesn't define SIG_ERR */
#if    defined(SIG_IGN) && !defined(SIG_ERR)
#define    SIG_ERR    ((Sigfunc *)-1)
#endif

#define    min(a,b)    ((a) < (b) ? (a) : (b))
#define    max(a,b)    ((a) > (b) ? (a) : (b))

                    /* prototypes for our own functions */
char    *path_alloc(int *);            /* {Prog pathalloc} */
int         open_max(void);            /* {Prog openmax} */
void     clr_fl(int, int);            /* {Prog setfl} */
void     set_fl(int, int);            /* {Prog setfl} */
void     pr_exit(int);                /* {Prog prexit} */
void     pr_mask(const char *);        /* {Prog prmask} */
Sigfunc    *signal_intr(int, Sigfunc *);/* {Prog signal_intr_function} */

int         tty_cbreak(int);            /* {Prog raw} */
int         tty_raw(int);                /* {Prog raw} */
int         tty_reset(int);            /* {Prog raw} */
void     tty_atexit(void);            /* {Prog raw} */
#ifdef    ECHO    /* only if has been included */
struct termios    *tty_termios(void);    /* {Prog raw} */
#endif

void     sleep_us(unsigned int);    /* {Ex sleepus} */
ssize_t     readn(int, void *, size_t);/* {Prog readn} */
ssize_t     writen(int, const void *, size_t);/* {Prog writen} */
int         daemon_init(void);            /* {Prog daemoninit} */

int         s_pipe(int *);                /* {Progs svr4_spipe bsd_spipe} */
int         recv_fd(int, ssize_t (*func)(int, const void *, size_t));
                                    /* {Progs recvfd_svr4 recvfd_43bsd} */
int         send_fd(int, int);            /* {Progs sendfd_svr4 sendfd_43bsd} */
int         send_err(int, int, const char *);/* {Prog senderr} */
int         serv_listen(const char *);    /* {Progs servlisten_svr4 servlisten_44bsd} */
int         serv_accept(int, uid_t *);    /* {Progs servaccept_svr4 servaccept_44bsd} */
int         cli_conn(const char *);    /* {Progs cliconn_svr4 cliconn_44bsd} */
int         buf_args(char *, int (*func)(int, char **));
                                    /* {Prog bufargs} */

int         ptym_open(char *);            /* {Progs ptyopen_svr4 ptyopen_44bsd} */
int         ptys_open(int, char *);    /* {Progs ptyopen_svr4 ptyopen_44bsd} */
#ifdef    TIOCGWINSZ
pid_t     pty_fork(int *, char *, const struct termios *,
                 const struct winsize *);    /* {Prog ptyfork} */
#endif

int        lock_reg(int, int, int, off_t, int, off_t);
                                    /* {Prog lockreg} */
#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)

pid_t    lock_test(int, int, off_t, int, off_t);
                                    /* {Prog locktest} */

#define    is_readlock(fd, offset, whence, len) \
            lock_test(fd, F_RDLCK, offset, whence, len)
#define    is_writelock(fd, offset, whence, len) \
            lock_test(fd, F_WRLCK, offset, whence, len)

void    err_dump(const char *, ...);    /* {App misc_source} */
void    err_msg(const char *, ...);
void    err_quit(const char *, ...);
void    err_ret(const char *, ...);
void    err_sys(const char *, ...);

void    log_msg(const char *, ...);        /* {App misc_source} */
void    log_open(const char *, int, int);
void    log_quit(const char *, ...);
void    log_ret(const char *, ...);
void    log_sys(const char *, ...);

void    TELL_WAIT(void);        /* parent/child from {Sec race_conditions} */
void    TELL_PARENT(pid_t);
void    TELL_CHILD(pid_t);
void    WAIT_PARENT(void);
void    WAIT_CHILD(void);

char    *pname = NULL;        /* caller can set this from argv[0] */

/* Nonfatal error related to a system call.
 * Print a message and return. */


void
err_ret(const char *fmt, ...)
{
    va_list        ap;

    va_start(ap, fmt);
    err_doit(1, fmt, ap);
    va_end(ap);
    return;
}

/* Fatal error related to a system call.
 * Print a message and terminate. */


void
err_sys(const char *fmt, ...)
{
    va_list        ap;

    va_start(ap, fmt);
    err_doit(1, fmt, ap);
    va_end(ap);
    exit(1);
}

/* Fatal error related to a system call.
 * Print a message, dump core, and terminate. */


void
err_dump(const char *fmt, ...)
{
    va_list        ap;

    va_start(ap, fmt);
    err_doit(1, fmt, ap);
    va_end(ap);
    abort();        /* dump core and terminate */
    exit(1);        /* shouldn't get here */
}

/* Nonfatal error unrelated to a system call.
 * Print a message and return. */


void
err_msg(const char *fmt, ...)
{
    va_list        ap;

    va_start(ap, fmt);
    err_doit(0, fmt, ap);
    va_end(ap);
    return;
}

/* Fatal error unrelated to a system call.
 * Print a message and terminate. */


void
err_quit(const char *fmt, ...)
{
    va_list        ap;

    va_start(ap, fmt);
    err_doit(0, fmt, ap);
    va_end(ap);
    exit(1);
}

/* Print a message and return to caller.
 * Caller specifies "errnoflag". */


static void
err_doit(int errnoflag, const char *fmt, va_list ap)
{
    int        errno_save;
    char    buf[MAXLINE];

    errno_save = errno;        /* value caller might want printed */
    vsprintf(buf, fmt, ap);
    if (errnoflag)
        sprintf(buf+strlen(buf), ": %s", strerror(errno_save));
    strcat(buf, "\n");
    fflush(stdout);        /* in case stdout and stderr are the same */
    fputs(buf, stderr);
    fflush(NULL);        /* flushes all stdio output streams */
    return;
}
static volatile sig_atomic_t    sigflag;
                                /* set nonzero by signal handler */
static sigset_t            newmask, oldmask, zeromask;

static void
sig_usr(int signo)    /* one signal handler for SIGUSR1 and SIGUSR2 */
{
    sigflag = 1;
    return;
}

void
TELL_WAIT()
{
    if (signal(SIGUSR1, sig_usr) == SIG_ERR)
        err_sys("signal(SIGINT) error");
    if (signal(SIGUSR2, sig_usr) == SIG_ERR)
        err_sys("signal(SIGQUIT) 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");
}

void
TELL_PARENT(pid_t pid)
{
    kill(pid, SIGUSR2);        /* tell parent we're done */
}

void
WAIT_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");
}
void
TELL_CHILD(pid_t pid)
{
    kill(pid, SIGUSR1);            /* tell child we're done */
}

void
WAIT_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");
}

static void lockabyte(const char *, int, off_t);

int
main(void)
{
    int        fd;
    pid_t    pid;

        /* Create a file and write two bytes to it */
    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) {            /* child */
        lockabyte("child", fd, 0);
        TELL_PARENT(getppid());
        WAIT_PARENT();
        lockabyte("child", fd, 1);

    } else {                        /* parent */
        lockabyte("parent", fd, 1);
        TELL_CHILD(pid);
        WAIT_CHILD();
        lockabyte("parent", fd, 0);
    }
    exit(0);
}
int
lock_reg(int fd, int cmd, int type, off_t offset, int whence, off_t len)
{
    struct flock    lock;

    lock.l_type = type;        /* F_RDLCK, F_WRLCK, F_UNLCK */
    lock.l_start = offset;    /* byte offset, relative to l_whence */
    lock.l_whence = whence;    /* SEEK_SET, SEEK_CUR, SEEK_END */
    lock.l_len = len;        /* #bytes (0 means to EOF) */

    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 %d\n", name, offset);
}



$ a . o u t
child:got the lock,byte 0
parent:got the lock,byte 1
child:writew_lock error:Deadlock situation detected/avoided
parent:got the lock,byte 0
检测到死锁时,内核必须选择一个进程收到出错返回。在本实例中,选择了子进程,这是
一个实现细节。当此程序在另一个系统上运行时,一半次数是子进程接到出错信息,另一半则

================================
12.3.3 锁的隐含继承和释放
关于记录锁的自动继承和释放有三条规则:
(1) 锁与进程、文件两方面有关。这有两重含意:第一重很明显,当一个进程终止时,它
所建立的锁全部释放;第二重意思就不很明显,任何时候关闭一个描述符时,则该进程通过这
一描述符可以存访的文件上的任何一把锁都被释放(这些锁都是该进程设置的)。这就意味着
如果执行下列四步:
fd1=open(pathname, ...);
read_lock(fd1, ...);
f d 2 = d u p ( f d 1 ) ;
c l o s e ( f d 2 ) ;
则在c l o s e(f d 2)后,在f d 1上设置的锁被释放。如果将d u p代换为o p e n,其效果也一样:
fd1=open(pathname, ...);
read_lock(fd1, ...);
fd2=open(pathname, ...);
2 8 0 U N I X环境高级编程
下载
c l o s e ( f d 2 ) ;
(2) 由f o r k产生的子程序不继承父进程所设置的锁。这意味着,若一个进程得到一把锁,然
后调用f o r k,那么对于父进程获得的锁而言,子进程被视为另一个进程,对于从父进程处继承
过来的任一描述符,子进程要调用f c n t l以获得它自己的锁。这与锁的作用是相一致的。锁的作
用是阻止多个进程同时写同一个文件(或同一文件区域)。如果子进程继承父进程的锁,则父、
子进程就可以同时写同一个文件。
(3) 在执行e x e c后,新程序可以继承原执行程序的锁。
P O S I X . 1没有要求这一点。但是,S V R 4和4 . 3 + B S D都支持这一点。
是父进程。
阅读(1359) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~