test_rlock.cpp

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>


#define test_file "test_rlock.sh"
#define test_file_content "#!/bin/shnnecho "this is rlock test!""

void close_file(int& fd);

void start_proc()
{
    printf("process %d startn", getpid());
}


void open_file(int& fd)
{
    fd = open(test_file, O_RDWR|O_CREAT);
    if(fd == -1)
        printf("[%d] open %s failedn", getpid(), test_file);
    else 
        printf("[%d] open write file %s success n", getpid(), test_file);
}

void write_file(int& fd) 
{
    if(fd < 0) 
        return;

    char buf[]=test_file_content;
    int sz=sizeof(buf);
    if(write(fd, buf, sz) != sz) {
        printf("[%d] write %d failedn", getpid(), sz);
        close_file(fd);
    } else
        printf("[%d] write file successedn", getpid());
}

void close_file(int& fd)
{
    if(fd < 0) 
        return;

    printf("[%d] close file %s n", getpid(), test_file);
    close(fd);
    fd = -1;
}


void set_lock(int& fd, short type, off_t start, short whence, off_t len)
{
    if(fd < 0)
        return;

    char tp[10];
    if(type == F_RDLCK)
        sprintf(tp, "%s", "rlock");
    else if(type == F_WRLCK)
        sprintf(tp, "%s", "wlock");
    else 
        sprintf(tp, "%s", "unlock");

    char st[10];
    if(whence == SEEK_SET)
        sprintf(st, "%s", "start");
    else if(whence == SEEK_END)
        sprintf(st, "%s", "end");
    else 
        sprintf(st, "%s", "current");        

    struct flock fk;
    fk.l_type = type;
    fk.l_start = start;
    fk.l_whence = whence;
    fk.l_len = len;
    fk.l_pid = getpid();

    if(fcntl(fd, F_SETLK, &fk) == -1) {
        printf("[%d] set [%s] from [%s] at [%d] length [%d] failed!n", getpid(), tp, st, start, len);
        perror("F_GETLK");
    } else
        printf("[%d] set [%s] from [%s] at [%d] length [%d] success!n", getpid(), tp, st, start, len);
}

void get_lock(int& fd, short type, off_t start, short whence, off_t len)
{
    if(fd < 0)
        return;

    char tp[10];
    if(type == F_RDLCK)
        sprintf(tp, "%s", "rlock");
    else if(type == F_WRLCK)
        sprintf(tp, "%s", "wlock");
    else 
        sprintf(tp, "%s", "unlock");

    char st[10];
    if(whence == SEEK_SET)
        sprintf(st, "%s", "start");
    else if(whence == SEEK_END)
        sprintf(st, "%s", "end");
    else 
        sprintf(st, "%s", "current");        

    struct flock fk;
    fk.l_type = type;
    fk.l_start = start;
    fk.l_whence = whence;
    fk.l_len = len;

    if(fcntl(fd, F_GETLK, &fk) == -1) {
        printf("[%d] get [%s] from [%s] at [%d] length [%d] failed!n", getpid(), tp, st, start, len);
        perror("F_GETLK");
    } else {
        char rtp[10];
        if(fk.l_type == F_UNLCK) {
            sprintf(rtp, "%s", "unlocked");
            printf("[%d] get [%s] [%s] from [%s] at [%d] length [%d]!n", getpid(), tp, rtp, st, start, len);
        } else {
            sprintf(rtp, "%s", "locked");
            printf("[%d] get [%s] [%s] from [%s] at [%d] length [%d] by process [%d]!n", getpid(), tp, rtp, st, start, len, fk.l_pid);
        }
    }
}


int main()
{
    pid_t pid;    
    int testfd = -1;

    start_proc();

    open_file(testfd);
    write_file(testfd);

    get_lock(testfd, F_WRLCK, 0, SEEK_SET, 1);

    set_lock(testfd, F_WRLCK, 0, SEEK_SET, 1);

    get_lock(testfd, F_WRLCK, 0, SEEK_SET, 1);

    get_lock(testfd, F_WRLCK, 0, SEEK_SET, 1);

    if((pid = fork()) < 0)
        perror("fork");
    else if(pid == 0) {
        // test inherent
        int testfd1 = -1;
        open_file(testfd1);
        get_lock(testfd1, F_WRLCK, 0, SEEK_SET, 1);
        set_lock(testfd1, F_RDLCK, 0, SEEK_SET, 1);

        // test close fd
        sleep(3);
        printf("[%d] get lock after parent exit!n", getpid());
        get_lock(testfd1, F_WRLCK, 0, SEEK_SET, 1);
        set_lock(testfd1, F_RDLCK, 0, SEEK_SET, 1);

        close_file(testfd1);
    } else {
        get_lock(testfd, F_WRLCK, 0, SEEK_SET, 1);
        sleep(2);
        close_file(testfd);
    }    
}