曲径通幽论坛

 找回密码
 立即注册
搜索
查看: 6795|回复: 0
打印 上一主题 下一主题

[文件I/O] 系统不支持强制性锁

[复制链接]

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34395
跳转到指定楼层
楼主
发表于 2009-7-15 14:46:21 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
测试系统为 OpenSuse11.1, CentOS5.3

测试代码
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <stdarg.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/wait.h>

volatile sig_atomic_t sigflag;
int pfd1[2], pfd2[2];
sigset_t    newmask, oldmask, zeromask;

void err_doit(int errnoflag, const char *fmt, va_list ap)
{
    int    errno_save;
    char    buf[4096];
   
    errno_save = errno;
    vsprintf(buf, fmt, ap);
    if (errnoflag)
       sprintf(buf+strlen(buf), ": %s", strerror(errno_save));
    strcat(buf, "\n");
    fflush(stdout);
    fputs(buf, stderr);
    fflush(stderr);
    return;
}

void err_sys(const char *fmt, ...)
{
    va_list        ap;
    va_start(ap, fmt);
    err_doit(1, fmt, ap);
    va_end(ap);
    exit(1);
}
void sig_usr(int signo)
{
    sigflag = 1;
    return;
}
TELL_WAIT()
{
    if (signal(SIGUSR1, sig_usr) == SIG_ERR)         /*SIGUSR1 为用户自定义信号*/
        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);
        /*阻塞 SIGUSR1 和 SIGUSR2 并且保存当前信号掩码*/
    if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)
        err_sys("SIG_BLOCK error");
}   

void WAIT_PARENT(void)
{
    while( sigflag == 0)
        sigsuspend(&zeromask);    /*suspend()取消了所有信号屏蔽,等待父进程发来信号*/
    sigflag = 0;
        /*恢复信号掩码*/
    if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
        err_sys("SIG_SETMASK 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) );
}

void set_fl(int fd, int 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 err_ret(const char *fmt, ...)
{
    va_list        ap;
    va_start(ap, fmt);
    err_doit(1, fmt, ap);
    va_end(ap);
    return;
}


int main(void)
{
    int        fd;
    pid_t        pid;
    char        buff[5];
    struct stat    statbuf;
   
    if ( (fd = open("templock", O_RDWR | O_CREAT | O_TRUNC, 0644)) < 0)
        err_sys("open error",buff);
   
    if (write(fd, "abcdef", 6) != 6)
        err_sys("write error");

    /*打开 set-group-ID(s-gid),并关闭组执行权限*/
    if (fstat(fd, &statbuf) < 0)
        err_sys("fstat error");
   
    if (fchmod(fd, (statbuf.st_mode & ~S_IXGRP) | S_ISGID) < 0)
        err_sys("fork error");
   
    TELL_WAIT();
    if ( (pid = fork()) < 0) {
        err_sys("fork error");
    } else if (pid > 0) {    /*父进程*/
                /*整个文件写锁*/
    if (lock_reg(fd, F_SETLK, F_WRLCK, 0, SEEK_SET, 0) < 0)
        err_sys("write_lock error");
    kill(pid, SIGUSR1);    /*给子进程发送信号告知锁完成*/
   
    if (waitpid(pid, NULL, 0) < 0)
        err_sys("waitpid error");
    } else {
            WAIT_PARENT();    /*等待父进程设置锁*/
   
    set_fl(fd, O_NONBLOCK);   
   
    if (lock_reg(fd, F_SETLK, F_RDLCK, 0, SEEK_SET, 0) != -1)
        err_sys("child: read_lock succeeded");
    printf("read_lock of already-locked region return %d\n", errno);

    if (lseek(fd, 0, SEEK_SET) == -1)
        err_sys("lseek, error");

    if (read(fd, buff, 2) < 0)
    err_ret("read failed (mandatory locking wroks)");
    else
        printf("read OK (no mandatory locking), buff = %2.2s\n", buff);
    }
    exit(0);
}
运行及输出
beyes@linux-beyes:~/C> ./manlock.exe
read_lock of already-locked region return 11
read OK (no mandatory locking), buff = ab

说明
如果系统支持强制性锁,那么强制性锁对其他进程的读写影响为:

阻塞描述符,试图
非阻塞描述符,试图

读                                 写
读                              写
在区域上的读锁
可以                          阻塞
可以                         EAGAIN
在区域上的写锁
阻塞                          阻塞
EAGAIN                  EAGAIN

在上面程序中,使用了强制性锁设置( fchmod(fd, (statbuf.st_mode & ~S_IXGRP) | S_ISGID ),然后对 templock 文件添加了一把写锁由程序。
假如系统支持强制性锁,那么templock中的内容可以读取,但由输出可见,可以读取 templock 中的内容,所以所测试的系统( opensuse11.1 centos5.3 )不支持强制性锁机制。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|曲径通幽 ( 琼ICP备11001422号-1|公安备案:46900502000207 )

GMT+8, 2025-5-3 23:22 , Processed in 0.106107 second(s), 22 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表