The purpose of this patch is to make the state diagram for lock_file
objects simpler and deterministic.

If locking fails, lock_file() sometimes leaves the lock_file object
partly initialized, but sometimes not. It sometimes registers the
object in lock_file_list, but sometimes not. This makes the state
diagram for lock_file objects effectively indeterministic and hard to
reason about. A future patch will also change the filename field into
a strbuf, which needs more involved initialization, so it will become
even more important that the state of a lock_file object is
well-defined after a failed attempt to lock.

The ambiguity doesn't currently have any ill effects, because
lock_file objects cannot be removed from the lock_file_list anyway.
But to make it easier to document and reason about the code, make this
behavior inconsistent: *always* initialize the lock_file object and
*always* register it in lock_file_list the first time it is used,
regardless of whether an error occurs.

While we're at it, make sure that all of the lock_file fields are
initialized to values appropriate for an unlocked object; the caller
is only responsible for making sure that on_list is set to zero before
the first time it is used.

Signed-off-by: Michael Haggerty <mhag...@alum.mit.edu>
---
 lockfile.c | 25 ++++++++++++++++---------
 1 file changed, 16 insertions(+), 9 deletions(-)

diff --git a/lockfile.c b/lockfile.c
index f4ce79b..81143e5 100644
--- a/lockfile.c
+++ b/lockfile.c
@@ -129,6 +129,22 @@ static int lock_file(struct lock_file *lk, const char 
*path, int flags)
         */
        static const size_t max_path_len = sizeof(lk->filename) - 5;
 
+       if (!lock_file_list) {
+               /* One-time initialization */
+               sigchain_push_common(remove_lock_file_on_signal);
+               atexit(remove_lock_file);
+       }
+
+       if (!lk->on_list) {
+               /* Initialize *lk and add it to lock_file_list: */
+               lk->fd = -1;
+               lk->owner = 0;
+               lk->filename[0] = 0;
+               lk->next = lock_file_list;
+               lock_file_list = lk;
+               lk->on_list = 1;
+       }
+
        if (strlen(path) >= max_path_len) {
                errno = ENAMETOOLONG;
                return -1;
@@ -139,16 +155,7 @@ static int lock_file(struct lock_file *lk, const char 
*path, int flags)
        strcat(lk->filename, ".lock");
        lk->fd = open(lk->filename, O_RDWR | O_CREAT | O_EXCL, 0666);
        if (0 <= lk->fd) {
-               if (!lock_file_list) {
-                       sigchain_push_common(remove_lock_file_on_signal);
-                       atexit(remove_lock_file);
-               }
                lk->owner = getpid();
-               if (!lk->on_list) {
-                       lk->next = lock_file_list;
-                       lock_file_list = lk;
-                       lk->on_list = 1;
-               }
                if (adjust_shared_perm(lk->filename)) {
                        int save_errno = errno;
                        error("cannot fix permission bits on %s",
-- 
2.1.0

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to