⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lock.c

📁 Minix3.11的源码。[MINIX 3是一个为高可靠性应用而设计的自由且简洁的类UNIX系统。]
💻 C
字号:
/* This file handles advisory file locking as required by POSIX. * * The entry points into this file are *   lock_op:	perform locking operations for FCNTL system call *   lock_revive: revive processes when a lock is released */#include "fs.h"#include <minix/com.h>#include <fcntl.h>#include <unistd.h>#include "file.h"#include "fproc.h"#include "inode.h"#include "lock.h"#include "param.h"/*===========================================================================* *				lock_op					     * *===========================================================================*/PUBLIC int lock_op(f, req)struct filp *f;int req;			/* either F_SETLK or F_SETLKW */{/* Perform the advisory locking required by POSIX. */  int r, ltype, i, conflict = 0, unlocking = 0;  mode_t mo;  off_t first, last;  struct flock flock;  vir_bytes user_flock;  struct file_lock *flp, *flp2, *empty;  /* Fetch the flock structure from user space. */  user_flock = (vir_bytes) m_in.name1;  r = sys_datacopy(who, (vir_bytes) user_flock,	FS_PROC_NR, (vir_bytes) &flock, (phys_bytes) sizeof(flock));  if (r != OK) return(EINVAL);  /* Make some error checks. */  ltype = flock.l_type;  mo = f->filp_mode;  if (ltype != F_UNLCK && ltype != F_RDLCK && ltype != F_WRLCK) return(EINVAL);  if (req == F_GETLK && ltype == F_UNLCK) return(EINVAL);  if ( (f->filp_ino->i_mode & I_TYPE) != I_REGULAR) return(EINVAL);  if (req != F_GETLK && ltype == F_RDLCK && (mo & R_BIT) == 0) return(EBADF);  if (req != F_GETLK && ltype == F_WRLCK && (mo & W_BIT) == 0) return(EBADF);  /* Compute the first and last bytes in the lock region. */  switch (flock.l_whence) {	case SEEK_SET:	first = 0; break;	case SEEK_CUR:	first = f->filp_pos; break;	case SEEK_END:	first = f->filp_ino->i_size; break;	default:	return(EINVAL);  }  /* Check for overflow. */  if (((long)flock.l_start > 0) && ((first + flock.l_start) < first))	return(EINVAL);  if (((long)flock.l_start < 0) && ((first + flock.l_start) > first))	return(EINVAL);  first = first + flock.l_start;  last = first + flock.l_len - 1;  if (flock.l_len == 0) last = MAX_FILE_POS;  if (last < first) return(EINVAL);  /* Check if this region conflicts with any existing lock. */  empty = (struct file_lock *) 0;  for (flp = &file_lock[0]; flp < & file_lock[NR_LOCKS]; flp++) {	if (flp->lock_type == 0) {		if (empty == (struct file_lock *) 0) empty = flp;		continue;	/* 0 means unused slot */	}	if (flp->lock_inode != f->filp_ino) continue;	/* different file */	if (last < flp->lock_first) continue;	/* new one is in front */	if (first > flp->lock_last) continue;	/* new one is afterwards */	if (ltype == F_RDLCK && flp->lock_type == F_RDLCK) continue;	if (ltype != F_UNLCK && flp->lock_pid == fp->fp_pid) continue;  	/* There might be a conflict.  Process it. */	conflict = 1;	if (req == F_GETLK) break;	/* If we are trying to set a lock, it just failed. */	if (ltype == F_RDLCK || ltype == F_WRLCK) {		if (req == F_SETLK) {			/* For F_SETLK, just report back failure. */			return(EAGAIN);		} else {			/* For F_SETLKW, suspend the process. */			suspend(XLOCK);			return(SUSPEND);		}	}	/* We are clearing a lock and we found something that overlaps. */	unlocking = 1;	if (first <= flp->lock_first && last >= flp->lock_last) {		flp->lock_type = 0;	/* mark slot as unused */		nr_locks--;		/* number of locks is now 1 less */		continue;	}	/* Part of a locked region has been unlocked. */	if (first <= flp->lock_first) {		flp->lock_first = last + 1;		continue;	}	if (last >= flp->lock_last) {		flp->lock_last = first - 1;		continue;	}		/* Bad luck. A lock has been split in two by unlocking the middle. */	if (nr_locks == NR_LOCKS) return(ENOLCK);	for (i = 0; i < NR_LOCKS; i++)		if (file_lock[i].lock_type == 0) break;	flp2 = &file_lock[i];	flp2->lock_type = flp->lock_type;	flp2->lock_pid = flp->lock_pid;	flp2->lock_inode = flp->lock_inode;	flp2->lock_first = last + 1;	flp2->lock_last = flp->lock_last;	flp->lock_last = first - 1;	nr_locks++;  }  if (unlocking) lock_revive();  if (req == F_GETLK) {	if (conflict) {		/* GETLK and conflict. Report on the conflicting lock. */		flock.l_type = flp->lock_type;		flock.l_whence = SEEK_SET;		flock.l_start = flp->lock_first;		flock.l_len = flp->lock_last - flp->lock_first + 1;		flock.l_pid = flp->lock_pid;	} else {		/* It is GETLK and there is no conflict. */		flock.l_type = F_UNLCK;	}	/* Copy the flock structure back to the caller. */	r = sys_datacopy(FS_PROC_NR, (vir_bytes) &flock,		who, (vir_bytes) user_flock, (phys_bytes) sizeof(flock));	return(r);  }  if (ltype == F_UNLCK) return(OK);	/* unlocked a region with no locks */  /* There is no conflict.  If space exists, store new lock in the table. */  if (empty == (struct file_lock *) 0) return(ENOLCK);	/* table full */  empty->lock_type = ltype;  empty->lock_pid = fp->fp_pid;  empty->lock_inode = f->filp_ino;  empty->lock_first = first;  empty->lock_last = last;  nr_locks++;  return(OK);}/*===========================================================================* *				lock_revive				     * *===========================================================================*/PUBLIC void lock_revive(){/* Go find all the processes that are waiting for any kind of lock and  * revive them all.  The ones that are still blocked will block again when  * they run.  The others will complete.  This strategy is a space-time  * tradeoff.  Figuring out exactly which ones to unblock now would take  * extra code, and the only thing it would win would be some performance in  * extremely rare circumstances (namely, that somebody actually used  * locking). */  int task;  struct fproc *fptr;  for (fptr = &fproc[INIT_PROC_NR + 1]; fptr < &fproc[NR_PROCS]; fptr++){	task = -fptr->fp_task;	if (fptr->fp_suspended == SUSPENDED && task == XLOCK) {		revive( (int) (fptr - fproc), 0);	}  }}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -