diff options
Diffstat (limited to 'contrib/cvs/src/lock.c')
-rw-r--r-- | contrib/cvs/src/lock.c | 170 |
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"); |