Tuesday, November 4, 2014

Unix Prog: Record locking(2)

1. deadlock

When using the fcntl to do the record locking, the operating system will automatically detect the deadlock when iterating all struct flock in vnode. If it detect one deadlock, fcntl will return error(<0).

lock.c:
 #include<stdio.h>  
 #include<stdlib.h>  
 #include<unistd.h>  
 #include<fcntl.h>  
 #include<signal.h>  
   
 #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))  
   
 volatile sig_atomic_t sigflag;  
 sigset_t newmask, oldmask, zeromask;  
   
 void sig_usr(int signo)  
 {  
  sigflag = 1;  
 }  
   
 void TELL_WAIT(void)  
 {  
  // Setup the signal handler  
  if(signal(SIGUSR1, sig_usr) == SIG_ERR) {  
   printf("signal error!\n");  
   exit(3);  
  }  
  if(signal(SIGUSR2, sig_usr) == SIG_ERR) {  
   printf("signal error!\n");  
   exit(3);  
  }  
   
  // Make signal mask  
  sigemptyset(&zeromask);  
  sigemptyset(&newmask);  
  sigaddset(&newmask, SIGUSR1);  
  sigaddset(&newmask, SIGUSR2);  
   
  // Block the SIGUSR1, SIGUSR2  
  if(sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0) {  
   printf("sigprocmask error!\n");  
   exit(4);  
  }  
 }  
   
 void TELL_PARENT(pid_t pid)  
 {  
  kill(pid, SIGUSR2);  
 }  
   
 void WAIT_PARENT(void)  
 {  
  // Child Process wait for the SIGUSR1 from parent  
  while(sigflag == 0)  
   sigsuspend(&zeromask);  
  sigflag = 0;  
   
  // After receiving the SIGUSR1 from parent  
  if(sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) {  
   printf("sigprocmask error!\n");  
   exit(4);  
  }  
 }  
   
 void TELL_CHILD(pid_t pid)  
 {  
  kill(pid, SIGUSR1);  
 }  
   
 void WAIT_CHILD(void)  
 {  
  // Parent Process wait for the SIGUSR2 from child  
  while(sigflag == 0)  
   sigsuspend(&zeromask);  
  sigflag = 0;  
   
  // After receiving the SIGUSR2 from child  
  if(sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) {  
   printf("sigprocmask error!\n");  
   exit(4);  
  }  
 }  
   
 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 lockabyte(const char *name, int fd, off_t offset)  
 {  
  if(writew_lock(fd, offset, SEEK_SET, 1) < 0) {  
   printf("%s, writew_lock error!\n", name);  
   return;  
  }  
  printf("%s: got the lock, byte %ld\n", name, offset);  
 }  
   
 int main(int argc, char* argv[])  
 {  
  int fd;  
  pid_t pid;  
   
  if((fd = creat("templock", O_RDWR)) < 0) {  
   printf("creat error!\n");  
   exit(5);  
  }  
   
  if(write(fd, "ab", 2) != 2) {  
   printf("write error!\n");  
   exit(6);  
  }  
   
  TELL_WAIT();  
  if((pid = fork()) < 0) {  
   printf("fork error!\n");  
   exit(7);  
  } 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);  
 }  

shell:
the program's parent process try to lock byte 1 and then byte 0, its child process tries to lock byte 0 and then byte 1. When the child process tries to acquire the lock, the os detect the deadlock, then child process exits. After it exits, all its lock are released. Finally parent process acquire the lock.
 ubuntu@ip-172-31-23-227:~$ ./lock.out  
 parent: got the lock, byte 1  
 child: got the lock, byte 0  
 child, writew_lock error!  
 parent: got the lock, byte 0  

No comments:

Post a Comment