summaryrefslogtreecommitdiff
path: root/contrib/cvs/src/lock.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/cvs/src/lock.c')
-rw-r--r--contrib/cvs/src/lock.c170
1 files changed, 113 insertions, 57 deletions
diff --git a/contrib/cvs/src/lock.c b/contrib/cvs/src/lock.c
index 9333d9b93e449..16e99d892717a 100644
--- a/contrib/cvs/src/lock.c
+++ b/contrib/cvs/src/lock.c
@@ -55,26 +55,28 @@
1. Check for EROFS. Maybe useful, although in the presence of NFS
EROFS does *not* mean that the file system is unchanging.
- 2. Provide a means to put the cvs locks in some directory apart from
- the repository (CVSROOT/locks; a -l option in modules; etc.).
-
- 3. Provide an option to disable locks for operations which only
+ 2. Provide an option to disable locks for operations which only
read (see above for some of the consequences).
- 4. Have a server internally do the locking. Probably a good
+ 3. Have a server internally do the locking. Probably a good
long-term solution, and many people have been working hard on code
changes which would eventually make it possible to have a server
which can handle various connections in one process, but there is
- much, much work still to be done before this is feasible.
-
- 5. Like #4 but use shared memory or something so that the servers
- merely need to all be on the same machine. This is a much smaller
- change to CVS (it functions much like #2; shared memory might be an
- unneeded complication although it presumably would be faster). */
+ much, much work still to be done before this is feasible. */
#include "cvs.h"
#include <assert.h>
+#ifdef HAVE_NANOSLEEP
+# include "xtime.h"
+#else /* HAVE_NANOSLEEP */
+# if !defined HAVE_USLEEP && defined HAVE_SELECT
+ /* use select as a workaround */
+# include "xselect.h"
+# endif /* !defined HAVE_USLEEP && defined HAVE_SELECT */
+#endif /* !HAVE_NANOSLEEP */
+
+
struct lock {
/* This is the directory in which we may have a lock named by the
readlock variable, a lock named by the writelock variable, and/or
@@ -341,7 +343,7 @@ unlock_proc (p, closure)
Node *p;
void *closure;
{
- lock_simple_remove ((struct lock *)p->data);
+ lock_simple_remove (p->data);
return (0);
}
@@ -388,6 +390,8 @@ lock_simple_remove (lock)
}
}
+
+
/*
* Create a lock file for readers
*/
@@ -404,13 +408,13 @@ Reader_Lock (xrepository)
xrepository);
if (noexec)
- return (0);
+ return 0;
/* we only do one directory at a time for read locks! */
if (global_readlock.repository != NULL)
{
error (0, 0, "Reader_Lock called while read locks set - Help!");
- return (1);
+ return 1;
}
if (readlock == NULL)
@@ -439,7 +443,7 @@ Reader_Lock (xrepository)
/* We don't set global_readlock.repository to NULL. I think this
only works because recurse.c will give a fatal error if we return
a nonzero value. */
- return (1);
+ return 1;
}
/* write a read-lock */
@@ -458,9 +462,11 @@ Reader_Lock (xrepository)
/* free the lock dir */
clear_lock (&global_readlock);
- return (err);
+ return err;
}
+
+
/*
* Lock a list of directories for writing
*/
@@ -476,13 +482,13 @@ Writer_Lock (list)
char *wait_repos;
if (noexec)
- return (0);
+ return 0;
/* We only know how to do one list at a time */
if (locklist != (List *) NULL)
{
error (0, 0, "Writer_Lock called while write locks set - Help!");
- return (1);
+ return 1;
}
wait_repos = NULL;
@@ -505,7 +511,7 @@ Writer_Lock (list)
free (wait_repos);
Lock_Cleanup (); /* clean up any locks we set */
error (0, 0, "lock failed - giving up");
- return (1);
+ return 1;
case L_LOCKED: /* Someone already had a lock */
remove_locks (); /* clean up any locks we set */
@@ -519,18 +525,20 @@ Writer_Lock (list)
lock_obtained (wait_repos);
free (wait_repos);
}
- return (0);
+ return 0;
default:
if (wait_repos != NULL)
free (wait_repos);
error (0, 0, "unknown lock status %d in Writer_Lock",
lock_error);
- return (1);
+ return 1;
}
}
}
+
+
/*
* walklist proc for setting write locks
*/
@@ -541,14 +549,16 @@ set_writelock_proc (p, closure)
{
/* if some lock was not OK, just skip this one */
if (lock_error != L_OK)
- return (0);
+ return 0;
/* apply the write lock */
lock_error_repos = p->key;
- lock_error = write_lock ((struct lock *)p->data);
- return (0);
+ lock_error = write_lock (p->data);
+ return 0;
}
+
+
/*
* Create a lock file for writers returns L_OK if lock set ok, L_LOCKED if
* lock held by someone else or L_ERROR if an error occurred
@@ -591,7 +601,7 @@ write_lock (lock)
}
/* indicate we failed due to read locks instead of error */
- return (L_LOCKED);
+ return L_LOCKED;
}
/* write the write-lock file */
@@ -613,15 +623,17 @@ write_lock (lock)
error (0, xerrno, "cannot create write lock in repository `%s'",
lock->repository);
free (tmp);
- return (L_ERROR);
+ return L_ERROR;
}
free (tmp);
- return (L_OK);
+ return L_OK;
}
else
- return (status);
+ return status;
}
+
+
/*
* readers_exist() returns 0 if there are no reader lock files remaining in
* the repository; else 1 is returned, to indicate that the caller should
@@ -631,6 +643,7 @@ static int
readers_exist (repository)
char *repository;
{
+ char *lockdir;
char *line;
DIR *dirp;
struct dirent *dp;
@@ -638,12 +651,15 @@ readers_exist (repository)
int ret;
#ifdef CVS_FUDGELOCKS
time_t now;
- (void) time (&now);
+ (void)time (&now);
#endif
+ lockdir = lock_name (repository, "");
+ lockdir[strlen (lockdir) - 1] = '\0'; /* remove trailing slash */
+
do {
- if ((dirp = CVS_OPENDIR (repository)) == NULL)
- error (1, 0, "cannot open directory %s", repository);
+ if ((dirp = CVS_OPENDIR (lockdir)) == NULL)
+ error (1, 0, "cannot open directory %s", lockdir);
ret = 0;
errno = 0;
@@ -651,13 +667,9 @@ readers_exist (repository)
{
if (CVS_FNMATCH (CVSRFLPAT, dp->d_name, 0) == 0)
{
- /* ignore our own readlock, if any */
- if (readlock && strcmp (readlock, dp->d_name) == 0)
- continue;
-
- line = xmalloc (strlen (repository) + strlen (dp->d_name) + 5);
- (void) sprintf (line, "%s/%s", repository, dp->d_name);
- if ( CVS_STAT (line, &sb) != -1)
+ line = xmalloc (strlen (lockdir) + 1 + strlen (dp->d_name) + 1);
+ (void)sprintf (line, "%s/%s", lockdir, dp->d_name);
+ if (CVS_STAT (line, &sb) != -1)
{
#ifdef CVS_FUDGELOCKS
/*
@@ -677,9 +689,10 @@ readers_exist (repository)
}
else
{
- /* If the file doesn't exist, it just means that it disappeared
- between the time we did the readdir and the time we did
- the stat. */
+ /* If the file doesn't exist, it just means that it
+ * disappeared between the time we did the readdir and the
+ * time we did the stat.
+ */
if (!existence_error (errno))
error (0, errno, "cannot stat %s", line);
}
@@ -695,9 +708,14 @@ readers_exist (repository)
CVS_CLOSEDIR (dirp);
} while (ret < 0);
- return (ret);
+
+ if (lockdir != NULL)
+ free (lockdir);
+ return ret;
}
+
+
/*
* Set the static variable lockers_name appropriately, based on the stat
* structure passed in.
@@ -710,22 +728,29 @@ set_lockers_name (statp)
if (lockers_name != NULL)
free (lockers_name);
- if ((pw = (struct passwd *) getpwuid (statp->st_uid)) !=
- (struct passwd *) NULL)
+ if ((pw = (struct passwd *)getpwuid (statp->st_uid)) !=
+ (struct passwd *)NULL)
{
lockers_name = xstrdup (pw->pw_name);
}
else
{
lockers_name = xmalloc (20);
- (void) sprintf (lockers_name, "uid%lu", (unsigned long) statp->st_uid);
+ (void)sprintf (lockers_name, "uid%lu", (unsigned long) statp->st_uid);
}
}
+
+
/*
- * Persistently tries to make the directory "lckdir",, which serves as a
- * lock. If the create time on the directory is greater than CVSLCKAGE
+ * Persistently tries to make the directory "lckdir", which serves as a
+ * lock.
+ *
+ * #ifdef CVS_FUDGELOCKS
+ * If the create time on the directory is greater than CVSLCKAGE
* seconds old, just try to remove the directory.
+ * #endif
+ *
*/
static int
set_lock (lock, will_wait)
@@ -733,6 +758,7 @@ set_lock (lock, will_wait)
int will_wait;
{
int waited;
+ long us;
struct stat sb;
mode_t omask;
#ifdef CVS_FUDGELOCKS
@@ -749,6 +775,7 @@ set_lock (lock, will_wait)
* directory before they exit.
*/
waited = 0;
+ us = 1;
lock->have_lckdir = 0;
for (;;)
{
@@ -810,6 +837,33 @@ set_lock (lock, will_wait)
/* if he wasn't willing to wait, return an error */
if (!will_wait)
return (L_LOCKED);
+
+ /* if possible, try a very short sleep without a message */
+ if (!waited && us < 1000)
+ {
+ us += us;
+#if defined HAVE_NANOSLEEP
+ {
+ struct timespec ts;
+ ts.tv_sec = 0;
+ ts.tv_nsec = us * 1000;
+ (void)nanosleep (&ts, NULL);
+ continue;
+ }
+#elif defined HAVE_USLEEP
+ (void)usleep (us);
+ continue;
+#elif defined HAVE_SELECT
+ {
+ struct timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = us;
+ (void)select (0, (fd_set *)NULL, (fd_set *)NULL, (fd_set *)NULL, &tv);
+ continue;
+ }
+#endif
+ }
+
lock_wait (lock->repository);
waited = 1;
}
@@ -877,10 +931,13 @@ lock_obtained (repos)
cvs_flusherr ();
free (msg);
}
-
+
+
+
static int lock_filesdoneproc PROTO ((void *callerdat, int err,
- char *repository, char *update_dir,
- List *entries));
+ const char *repository,
+ const char *update_dir,
+ List *entries));
/*
* Create a list of repositories to lock
@@ -890,8 +947,8 @@ static int
lock_filesdoneproc (callerdat, err, repository, update_dir, entries)
void *callerdat;
int err;
- char *repository;
- char *update_dir;
+ const char *repository;
+ const char *update_dir;
List *entries;
{
Node *p;
@@ -917,16 +974,15 @@ lock_tree_for_write (argc, argv, local, which, aflag)
int which;
int aflag;
{
- int err;
/*
* Run the recursion processor to find all the dirs to lock and lock all
* the dirs
*/
lock_tree_list = getlist ();
- err = start_recursion ((FILEPROC) NULL, lock_filesdoneproc,
- (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL, argc,
- argv, local, which, aflag, CVS_LOCK_NONE,
- (char *) NULL, 0);
+ start_recursion ((FILEPROC) NULL, lock_filesdoneproc,
+ (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL, argc,
+ argv, local, which, aflag, CVS_LOCK_NONE,
+ (char *) NULL, 0, (char *) NULL);
sortlist (lock_tree_list, fsortcmp);
if (Writer_Lock (lock_tree_list) != 0)
error (1, 0, "lock failed - giving up");