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

📄 lock.c

📁 一个简单的操作系统minix的核心代码
💻 C
字号:
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
				src/fs/lock.c	 	 
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

22300	/* This file handles advisory file locking as required by POSIX.
22301	 *
22302	 * The entry points into this file are
22303	 *   lock_op:   perform locking operations for FCNTL system call
22304	 *   lock_revive: revive processes when a lock is released
22305	 */
22306	
22307	#include "fs.h"
22308	#include <fcntl.h>
22309	#include <unistd.h>     /* cc runs out of memory with unistd.h :-( */
22310	#include "file.h"
22311	#include "fproc.h"
22312	#include "inode.h"
22313	#include "lock.h"
22314	#include "param.h"
22315	
22316	/*===========================================================================*
22317	 *                              lock_op                                      *
22318	 *===========================================================================*/
22319	PUBLIC int lock_op(f, req)
22320	struct filp *f;
22321	int req;                        /* either F_SETLK or F_SETLKW */
22322	{
22323	/* Perform the advisory locking required by POSIX. */
22324	
22325	  int r, ltype, i, conflict = 0, unlocking = 0;
22326	  mode_t mo;
22327	  off_t first, last;
22328	  struct flock flock;
22329	  vir_bytes user_flock;
22330	  struct file_lock *flp, *flp2, *empty;
22331	
22332	  /* Fetch the flock structure from user space. */
22333	  user_flock = (vir_bytes) name1;
22334	  r = sys_copy(who, D, (phys_bytes) user_flock,
22335	        FS_PROC_NR, D, (phys_bytes) &flock, (phys_bytes) sizeof(flock));
22336	  if (r != OK) return(EINVAL);
22337	
22338	  /* Make some error checks. */
22339	  ltype = flock.l_type;
22340	  mo = f->filp_mode;
22341	  if (ltype != F_UNLCK && ltype != F_RDLCK && ltype != F_WRLCK) return(EINVAL);
22342	  if (req == F_GETLK && ltype == F_UNLCK) return(EINVAL);
22343	  if ( (f->filp_ino->i_mode & I_TYPE) != I_REGULAR) return(EINVAL);
22344	  if (req != F_GETLK && ltype == F_RDLCK && (mo & R_BIT) == 0) return(EBADF);
22345	  if (req != F_GETLK && ltype == F_WRLCK && (mo & W_BIT) == 0) return(EBADF);
22346	
22347	  /* Compute the first and last bytes in the lock region. */
22348	  switch (flock.l_whence) {
22349	        case SEEK_SET:  first = 0; break;
22350	        case SEEK_CUR:  first = f->filp_pos; break;
22351	        case SEEK_END:  first = f->filp_ino->i_size; break;
22352	        default:        return(EINVAL);
22353	  }
22354	  /* Check for overflow. */
22355	  if (((long)flock.l_start > 0) && ((first + flock.l_start) < first))
22356	        return(EINVAL);
22357	  if (((long)flock.l_start < 0) && ((first + flock.l_start) > first))
22358	        return(EINVAL);
22359	  first = first + flock.l_start;
22360	  last = first + flock.l_len - 1;
22361	  if (flock.l_len == 0) last = MAX_FILE_POS;
22362	  if (last < first) return(EINVAL);
22363	
22364	  /* Check if this region conflicts with any existing lock. */
22365	  empty = (struct file_lock *) 0;
22366	  for (flp = &file_lock[0]; flp < & file_lock[NR_LOCKS]; flp++) {
22367	        if (flp->lock_type == 0) {
22368	                if (empty == (struct file_lock *) 0) empty = flp;
22369	                continue;       /* 0 means unused slot */
22370	        }
22371	        if (flp->lock_inode != f->filp_ino) continue;   /* different file */
22372	        if (last < flp->lock_first) continue;   /* new one is in front */
22373	        if (first > flp->lock_last) continue;   /* new one is afterwards */
22374	        if (ltype == F_RDLCK && flp->lock_type == F_RDLCK) continue;
22375	        if (ltype != F_UNLCK && flp->lock_pid == fp->fp_pid) continue;
22376	  
22377	        /* There might be a conflict.  Process it. */
22378	        conflict = 1;
22379	        if (req == F_GETLK) break;
22380	
22381	        /* If we are trying to set a lock, it just failed. */
22382	        if (ltype == F_RDLCK || ltype == F_WRLCK) {
22383	                if (req == F_SETLK) {
22384	                        /* For F_SETLK, just report back failure. */
22385	                        return(EAGAIN);
22386	                } else {
22387	                        /* For F_SETLKW, suspend the process. */
22388	                        suspend(XLOCK);
22389	                        return(0);
22390	                }
22391	        }
22392	
22393	        /* We are clearing a lock and we found something that overlaps. */
22394	        unlocking = 1;
22395	        if (first <= flp->lock_first && last >= flp->lock_last) {
22396	                flp->lock_type = 0;     /* mark slot as unused */
22397	                nr_locks--;             /* number of locks is now 1 less */
22398	                continue;
22399	        }
22400	
22401	        /* Part of a locked region has been unlocked. */
22402	        if (first <= flp->lock_first) {
22403	                flp->lock_first = last + 1;
22404	                continue;
22405	        }
22406	
22407	        if (last >= flp->lock_last) {
22408	                flp->lock_last = first - 1;
22409	                continue;
22410	        }
22411	        
22412	        /* Bad luck. A lock has been split in two by unlocking the middle. */
22413	        if (nr_locks == NR_LOCKS) return(ENOLCK);
22414	        for (i = 0; i < NR_LOCKS; i++)
22415	                if (file_lock[i].lock_type == 0) break;
22416	        flp2 = &file_lock[i];
22417	        flp2->lock_type = flp->lock_type;
22418	        flp2->lock_pid = flp->lock_pid;
22419	        flp2->lock_inode = flp->lock_inode;
22420	        flp2->lock_first = last + 1;
22421	        flp2->lock_last = flp->lock_last;
22422	        flp->lock_last = first - 1;
22423	        nr_locks++;
22424	  }
22425	  if (unlocking) lock_revive();
22426	
22427	  if (req == F_GETLK) {
22428	        if (conflict) {
22429	                /* GETLK and conflict. Report on the conflicting lock. */
22430	                flock.l_type = flp->lock_type;
22431	                flock.l_whence = SEEK_SET;
22432	                flock.l_start = flp->lock_first;
22433	                flock.l_len = flp->lock_last - flp->lock_first + 1;
22434	                flock.l_pid = flp->lock_pid;
22435	
22436	        } else {
22437	                /* It is GETLK and there is no conflict. */
22438	                flock.l_type = F_UNLCK;
22439	        }
22440	
22441	        /* Copy the flock structure back to the caller. */
22442	        r = sys_copy(FS_PROC_NR, D, (phys_bytes) &flock,
22443	                who, D, (phys_bytes) user_flock, (phys_bytes) sizeof(flock));
22444	        return(r);
22445	  }
22446	
22447	  if (ltype == F_UNLCK) return(OK);     /* unlocked a region with no locks */
22448	
22449	  /* There is no conflict.  If space exists, store new lock in the table. */
22450	  if (empty == (struct file_lock *) 0) return(ENOLCK);  /* table full */
22451	  empty->lock_type = ltype;
22452	  empty->lock_pid = fp->fp_pid;
22453	  empty->lock_inode = f->filp_ino;
22454	  empty->lock_first = first;
22455	  empty->lock_last = last;
22456	  nr_locks++;
22457	  return(OK);
22458	}
	
22460	/*===========================================================================*
22461	 *                              lock_revive                                  *
22462	 *===========================================================================*/
22463	PUBLIC void lock_revive()
22464	{
22465	/* Go find all the processes that are waiting for any kind of lock and 
22466	 * revive them all.  The ones that are still blocked will block again when 
22467	 * they run.  The others will complete.  This strategy is a space-time 
22468	 * tradeoff.  Figuring out exactly which ones to unblock now would take 
22469	 * extra code, and the only thing it would win would be some performance in 
22470	 * extremely rare circumstances (namely, that somebody actually used 
22471	 * locking).
22472	 */
22473	
22474	  int task;
22475	  struct fproc *fptr;
22476	
22477	  for (fptr = &fproc[INIT_PROC_NR + 1]; fptr < &fproc[NR_PROCS]; fptr++){
22478	        task = -fptr->fp_task;
22479	        if (fptr->fp_suspended == SUSPENDED && task == XLOCK) {
22480	                revive( (int) (fptr - fproc), 0);
22481	        }
22482	  }
22483	}

⌨️ 快捷键说明

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