X-Git-Url: http://www.git.cypherpunks.ru/?a=blobdiff_plain;f=run.go;h=6366f4a0aad03c79272acf524a0cd8d8972843de;hb=f0f007ed9bb046289965d2a7e64f215e4a50a441;hp=ea14641a9304bd85adbee7c988cebdcc3059242c;hpb=d8abe40c66df8d79a025524c0d230959cacf9465;p=goredo.git diff --git a/run.go b/run.go index ea14641..6366f4a 100644 --- a/run.go +++ b/run.go @@ -1,6 +1,6 @@ /* goredo -- djb's redo implementation on pure Go -Copyright (C) 2020-2021 Sergey Matveev +Copyright (C) 2020-2022 Sergey Matveev This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -198,9 +198,14 @@ func runScript(tgtOrig string, errs chan error, traced bool) error { if err != nil { return TgtError{tgtOrig, err} } + flock := unix.Flock_t{ + Type: unix.F_WRLCK, + Whence: io.SeekStart, + } lockRelease := func() { tracef(CLock, "LOCK_UN: %s", fdLock.Name()) - if err := unix.Flock(int(fdLock.Fd()), unix.LOCK_UN); err != nil { + flock.Type = unix.F_UNLCK + if err := unix.FcntlFlock(fdLock.Fd(), unix.F_SETLK, &flock); err != nil { log.Fatalln(err) } fdLock.Close() @@ -208,13 +213,16 @@ func runScript(tgtOrig string, errs chan error, traced bool) error { tracef(CLock, "LOCK_NB: %s", fdLock.Name()) // Waiting for job completion, already taken by someone else - if err = unix.Flock(int(fdLock.Fd()), unix.LOCK_EX|unix.LOCK_NB); err != nil { - if uintptr(err.(syscall.Errno)) != uintptr(unix.EWOULDBLOCK) { + if err = unix.FcntlFlock(fdLock.Fd(), unix.F_SETLK, &flock); err != nil { + if uintptr(err.(syscall.Errno)) != uintptr(unix.EAGAIN) { fdLock.Close() return TgtError{tgtOrig, err} } Jobs.Add(1) - tracef(CDebug, "waiting: %s", tgtOrig) + if err = unix.FcntlFlock(fdLock.Fd(), unix.F_GETLK, &flock); err != nil { + log.Fatalln(err) + } + tracef(CDebug, "waiting: %s (pid=%d)", tgtOrig, flock.Pid) if FdStatus != nil { if _, err = FdStatus.Write([]byte{StatusWait}); err != nil { log.Fatalln(err) @@ -223,7 +231,7 @@ func runScript(tgtOrig string, errs chan error, traced bool) error { go func() { defer Jobs.Done() tracef(CLock, "LOCK_EX: %s", fdLock.Name()) - if err := unix.Flock(int(fdLock.Fd()), unix.LOCK_EX); err != nil { + if err := unix.FcntlFlock(fdLock.Fd(), unix.F_SETLKW, &flock); err != nil { log.Fatalln(err) } lockRelease() @@ -322,7 +330,7 @@ func runScript(tgtOrig string, errs chan error, traced bool) error { runErr.DoFile = doFileRelPath } - if err = writeDep(fdDep, cwdOrig, doFileRelPath); err != nil { + if err = depWrite(fdDep, cwdOrig, doFileRelPath); err != nil { cleanup() return TgtError{tgtOrig, err} } @@ -616,10 +624,9 @@ func runScript(tgtOrig string, errs chan error, traced bool) error { // Was $1 touched? if fd, err := os.Open(path.Join(cwdOrig, tgt)); err == nil { - errTouched := Err1WasTouched if inodePrev == nil { fd.Close() - runErr.Err = errTouched + runErr.Err = Err1WasTouched errs <- runErr return } @@ -631,7 +638,7 @@ func runScript(tgtOrig string, errs chan error, traced bool) error { return } if !inode.Equals(inodePrev) { - runErr.Err = errTouched + runErr.Err = Err1WasTouched errs <- runErr return } @@ -683,7 +690,7 @@ func runScript(tgtOrig string, errs chan error, traced bool) error { fd = fdStdout } - // Do we need to ifcreate it, of ifchange with renaming? + // Do we need to ifcreate it, or ifchange with renaming? if fd == nil { os.Remove(path.Join(cwdOrig, tgt)) err = ifcreate(fdDep, tgt) @@ -707,7 +714,7 @@ func runScript(tgtOrig string, errs chan error, traced bool) error { goto Finish } } - err = writeDep(fdDep, cwdOrig, tgt) + err = depWrite(fdDep, cwdOrig, tgt) if err != nil { goto Finish } @@ -731,6 +738,26 @@ func runScript(tgtOrig string, errs chan error, traced bool) error { goto Finish } } + + // Post-commit .rec sanitizing + fdDep.Close() + if fdDepR, err := os.Open(fdDepPath); err == nil { + depInfo, err := depRead(fdDepR) + fdDepR.Close() + if err != nil { + goto Finish + } + ifchangeSeen := make(map[string]struct{}, len(depInfo.ifchanges)) + for _, dep := range depInfo.ifchanges { + ifchangeSeen[dep["Target"]] = struct{}{} + } + for _, dep := range depInfo.ifcreates { + if _, exists := ifchangeSeen[dep]; exists { + tracef(CWarn, "simultaneous ifcreate and ifchange records: %s", tgt) + } + } + } + Finish: runErr.Err = err errs <- runErr