lockfile.cc #1

  • //
  • guest/
  • perforce_software/
  • p4/
  • 2014-2/
  • sys/
  • lockfile.cc
  • View
  • Commits
  • Open Download .zip Download (5 KB)
/*
 * Copyright 1995, 1996 Perforce Software.  All rights reserved.
 *
 * This file is part of Perforce - the FAST SCM System.
 */


# define NEED_FILE
# define NEED_FCNTL
# define NEED_FLOCK

# include <stdhdrs.h>
# include <lockfile.h>

# if defined( OS_SOLARIS ) && !defined( OS_SOLARIS25 )
# define flockL flock64
# define FL_SETLKW F_SETLKW64
# define FL_SETLK F_SETLK64
# define FL_GETLK F_GETLK64
# else
# define flockL flock
# define FL_SETLKW F_SETLKW
# define FL_SETLK F_SETLK
# define FL_GETLK F_GETLK
# endif

# if defined ( OS_BEOS )
#include <SupportDefs.h>
extern "C" status_t _klock_node_(int fd);
extern "C" status_t _kunlock_node_(int fd);
#endif

int
lockFile( int fd, int flag )
{

# if defined( OS_OS2 ) || defined( MAC_MWPEF ) || defined( OS_VMS62 )

	return 0;
# else 
# if defined ( OS_BEOS )

	switch( flag )
	{
	case LOCKF_UN:    return _kunlock_node_(fd); 
	case LOCKF_SH:    
	case LOCKF_SH_NB: 
	case LOCKF_EX:    
	case LOCKF_EX_NB: return _klock_node_(fd); 
	}

	return -1;

# else
# ifdef OS_NT

	return lockFileByHandle( (HANDLE)_get_osfhandle( fd ), flag );
# else
# if defined(LOCK_UN) && !defined(sgi) && !defined(OS_QNX) && !defined(OS_AIX)

	switch( flag )
	{
	case LOCKF_UN:    return flock(fd, LOCK_UN); break;
	case LOCKF_SH:    return flock(fd, LOCK_SH); break;
	case LOCKF_SH_NB: return flock(fd, LOCK_SH|LOCK_NB); break;
	case LOCKF_EX:    return flock(fd, LOCK_EX); break;
	case LOCKF_EX_NB: return flock(fd, LOCK_EX|LOCK_NB); break;
	}

	return -1;

# else 
# if defined(OS_SOLARIS10)

	// fcntl on Solaris-10 behaves differently to previous releases and 
	// does not gel well with our locking strategy.  The following code 
	// is an attempt to fake up the locking behaviour that we desire,  
	// while hopefully not leading to writer starvation.

	// Instead of locking the whole file for readers,  region locks of 
	// 1 byte are taken at the callers pid address which will allow for 
	// multiple readers in the system since potential writers now only 
	// block on the first reader's single byte region.  This requires 
	// the use of F_GETLK to acquire the first blocking reader.

	int pid = getpid();
	struct flockL f;

	if( flag != LOCKF_EX )
	{
	    f.l_whence = SEEK_SET;
	    f.l_pid = pid;

	    switch( flag )
	    {
	    case LOCKF_EX_NB: 
	        f.l_start = 0;   f.l_len = 0; f.l_type = F_WRLCK; 
	        return fcntl( fd, FL_SETLK, &f );
	    case LOCKF_SH_NB: 
	        f.l_start = pid; f.l_len = 1; f.l_type = F_RDLCK; 
	        return fcntl( fd, FL_SETLK, &f );
	    case LOCKF_SH:    
	        f.l_start = pid; f.l_len = 1; f.l_type = F_RDLCK;
	        return fcntl( fd, FL_SETLKW, &f );
	    case LOCKF_UN:    
	        f.l_start = 0;   f.l_len = 0; f.l_type = F_UNLCK; 
	        return fcntl( fd, FL_SETLKW, &f );
	    }
	}

	// Handle exclusive blocking lock

	int noOtherLocks = 0;

	for( ;; )
	{
	    f.l_type = F_WRLCK;
	    f.l_whence = SEEK_SET;
	    f.l_pid = pid;
	    f.l_start = 0;
	    f.l_len = 0;

	    if( noOtherLocks )
	        return fcntl( fd, FL_SETLKW, &f );

	    fcntl( fd, FL_GETLK, &f );

	    if( f.l_type == F_RDLCK )
	    {
	        // wait on this single byte

	        f.l_start = f.l_pid;
	        f.l_whence = SEEK_SET;
	        f.l_type = F_WRLCK;
	        f.l_len = 1;
	        f.l_pid = pid;

	        fcntl( fd, FL_SETLKW, &f );  // wait on locks
	        f.l_type = F_UNLCK;
	        fcntl( fd, FL_SETLKW, &f );  // release lock
	        continue;                    // check again
	    }

	    noOtherLocks++;
	}

# else

	int cmd;
	struct flockL f;
	f.l_start = 0;
	f.l_len = 0;
	f.l_pid = getpid();
	f.l_whence = 0;
	switch( flag )
	{
	case LOCKF_UN:    cmd = FL_SETLKW; f.l_type = F_UNLCK; break;
	case LOCKF_SH:    cmd = FL_SETLKW; f.l_type = F_RDLCK; break;
	case LOCKF_SH_NB: cmd = FL_SETLK;  f.l_type = F_RDLCK; break;
	case LOCKF_EX:    cmd = FL_SETLKW; f.l_type = F_WRLCK; break;
	case LOCKF_EX_NB: cmd = FL_SETLK;  f.l_type = F_WRLCK; break;
	default:	
	                  return -1;
	}

	return fcntl( fd, cmd, &f );

# endif
# endif /* LOCK_UN */
# endif /* OS_BEOS */
# endif /* OS_NT */
# endif /* MAC_MWPEF */

}

#ifdef OS_NT
int
lockFileByHandle(HANDLE h, int flag )
{

	/*
	 * NtFlock: flock for windows NT called by bt_fio.cc in dbopen2.
	 */

	OVERLAPPED	ol;
	DWORD		f;
	ol.Internal	= 0;
	ol.InternalHigh	= 0;
	ol.Offset	= 0xFFFFFFFF;
	ol.OffsetHigh	= 0xFFFFFFFF;
	ol.hEvent	= 0;

	switch( flag )
	{
	case LOCKF_UN:    return UnlockFileEx(h, 0, 1, 0, &ol) ? 0 : -1;

	case LOCKF_SH:    f = 0; break;
	case LOCKF_SH_NB: f = LOCKFILE_FAIL_IMMEDIATELY; break;
	case LOCKF_EX:    f = LOCKFILE_EXCLUSIVE_LOCK; break;
	case LOCKF_EX_NB: f = LOCKFILE_FAIL_IMMEDIATELY|LOCKFILE_EXCLUSIVE_LOCK;
	                  break;
	default:
	                  return -1;
	}

	return LockFileEx(h, f, 0, 1, 0, &ol) ? 0 : -1;
}
#endif
# Change User Description Committed
#1 15903 Matt Attaway Everything should be happy now between the Workshop and the depot paths
//guest/perforce_software/p4/2014_2/sys/lockfile.cc
#1 15901 Matt Attaway Clean up code to fit modern Workshop naming standards
//guest/perforce_software/p4/2014.2/sys/lockfile.cc
#1 12189 Matt Attaway Initial (and much belated) drop of 2014.2 p4 source code