utils: Add 'fcntl-flock'.
* guix/utils.scm (%struct-flock, F_SETLKW, F_xxLCK): New variables. (fcntl-flock): New procedure. * tests/utils.scm ("fcntl-flock"): New test.
This commit is contained in:
parent
6bfec3edf5
commit
2cd5c0380e
|
@ -1,5 +1,5 @@
|
||||||
;;; GNU Guix --- Functional package management for GNU
|
;;; GNU Guix --- Functional package management for GNU
|
||||||
;;; Copyright © 2012, 2013 Ludovic Courtès <ludo@gnu.org>
|
;;; Copyright © 2012, 2013, 2014 Ludovic Courtès <ludo@gnu.org>
|
||||||
;;; Copyright © 2013 Mark H Weaver <mhw@netris.org>
|
;;; Copyright © 2013 Mark H Weaver <mhw@netris.org>
|
||||||
;;;
|
;;;
|
||||||
;;; This file is part of GNU Guix.
|
;;; This file is part of GNU Guix.
|
||||||
|
@ -34,7 +34,7 @@
|
||||||
#:use-module (ice-9 regex)
|
#:use-module (ice-9 regex)
|
||||||
#:use-module (ice-9 match)
|
#:use-module (ice-9 match)
|
||||||
#:use-module (ice-9 format)
|
#:use-module (ice-9 format)
|
||||||
#:autoload (system foreign) (pointer->procedure)
|
#:use-module (system foreign)
|
||||||
#:export (bytevector->base16-string
|
#:export (bytevector->base16-string
|
||||||
base16-string->bytevector
|
base16-string->bytevector
|
||||||
|
|
||||||
|
@ -43,6 +43,7 @@
|
||||||
nixpkgs-derivation*
|
nixpkgs-derivation*
|
||||||
|
|
||||||
compile-time-value
|
compile-time-value
|
||||||
|
fcntl-flock
|
||||||
memoize
|
memoize
|
||||||
default-keyword-arguments
|
default-keyword-arguments
|
||||||
substitute-keyword-arguments
|
substitute-keyword-arguments
|
||||||
|
@ -222,6 +223,67 @@ buffered data is lost."
|
||||||
"Evaluate the given Nixpkgs derivation at compile-time."
|
"Evaluate the given Nixpkgs derivation at compile-time."
|
||||||
(compile-time-value (nixpkgs-derivation attribute)))
|
(compile-time-value (nixpkgs-derivation attribute)))
|
||||||
|
|
||||||
|
|
||||||
|
;;;
|
||||||
|
;;; Advisory file locking.
|
||||||
|
;;;
|
||||||
|
|
||||||
|
(define %struct-flock
|
||||||
|
;; 'struct flock' from <fcntl.h>.
|
||||||
|
(list short ; l_type
|
||||||
|
short ; l_whence
|
||||||
|
size_t ; l_start
|
||||||
|
size_t ; l_len
|
||||||
|
int)) ; l_pid
|
||||||
|
|
||||||
|
(define F_SETLKW
|
||||||
|
;; On Linux-based systems, this is usually 7, but not always
|
||||||
|
;; (exceptions include SPARC.) On GNU/Hurd, it's 9.
|
||||||
|
(compile-time-value
|
||||||
|
(cond ((string-contains %host-type "sparc") 9) ; sparc-*-linux-gnu
|
||||||
|
((string-contains %host-type "linux") 7) ; *-linux-gnu
|
||||||
|
(else 9)))) ; *-gnu*
|
||||||
|
|
||||||
|
(define F_xxLCK
|
||||||
|
;; The F_RDLCK, F_WRLCK, and F_UNLCK constants.
|
||||||
|
(compile-time-value
|
||||||
|
(cond ((string-contains %host-type "sparc") #(1 2 3)) ; sparc-*-linux-gnu
|
||||||
|
((string-contains %host-type "hppa") #(1 2 3)) ; hppa-*-linux-gnu
|
||||||
|
((string-contains %host-type "linux") #(0 1 2)) ; *-linux-gnu
|
||||||
|
(else #(1 2 3))))) ; *-gnu*
|
||||||
|
|
||||||
|
(define fcntl-flock
|
||||||
|
(let* ((ptr (dynamic-func "fcntl" (dynamic-link)))
|
||||||
|
(proc (pointer->procedure int ptr `(,int ,int *))))
|
||||||
|
(lambda (fd-or-port operation)
|
||||||
|
"Perform locking OPERATION on the file beneath FD-OR-PORT. OPERATION
|
||||||
|
must be a symbol, one of 'read-lock, 'write-lock, or 'unlock."
|
||||||
|
(define (operation->int op)
|
||||||
|
(case op
|
||||||
|
((read-lock) (vector-ref F_xxLCK 0))
|
||||||
|
((write-lock) (vector-ref F_xxLCK 1))
|
||||||
|
((unlock) (vector-ref F_xxLCK 2))
|
||||||
|
(else (error "invalid fcntl-flock operation" op))))
|
||||||
|
|
||||||
|
(define fd
|
||||||
|
(if (port? fd-or-port)
|
||||||
|
(fileno fd-or-port)
|
||||||
|
fd-or-port))
|
||||||
|
|
||||||
|
;; XXX: 'fcntl' is a vararg function, but here we happily use the
|
||||||
|
;; standard ABI; crossing fingers.
|
||||||
|
(let ((err (proc fd
|
||||||
|
F_SETLKW ; lock & wait
|
||||||
|
(make-c-struct %struct-flock
|
||||||
|
(list (operation->int operation)
|
||||||
|
SEEK_SET
|
||||||
|
0 0 ; whole file
|
||||||
|
0)))))
|
||||||
|
(or (zero? err)
|
||||||
|
|
||||||
|
;; Presumably we got EAGAIN or so.
|
||||||
|
(throw 'flock-error fd))))))
|
||||||
|
|
||||||
|
|
||||||
;;;
|
;;;
|
||||||
;;; Miscellaneous.
|
;;; Miscellaneous.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
;;; GNU Guix --- Functional package management for GNU
|
;;; GNU Guix --- Functional package management for GNU
|
||||||
;;; Copyright © 2012, 2013 Ludovic Courtès <ludo@gnu.org>
|
;;; Copyright © 2012, 2013, 2014 Ludovic Courtès <ludo@gnu.org>
|
||||||
;;;
|
;;;
|
||||||
;;; This file is part of GNU Guix.
|
;;; This file is part of GNU Guix.
|
||||||
;;;
|
;;;
|
||||||
|
@ -139,6 +139,36 @@
|
||||||
(append pids1 pids2)))
|
(append pids1 pids2)))
|
||||||
(equal? (get-bytevector-all decompressed) data)))))
|
(equal? (get-bytevector-all decompressed) data)))))
|
||||||
|
|
||||||
|
(test-equal "fcntl-flock"
|
||||||
|
0 ; the child's exit status
|
||||||
|
(let ((file (open-input-file (search-path %load-path "guix.scm"))))
|
||||||
|
(fcntl-flock file 'read-lock)
|
||||||
|
(match (primitive-fork)
|
||||||
|
(0
|
||||||
|
(dynamic-wind
|
||||||
|
(const #t)
|
||||||
|
(lambda ()
|
||||||
|
;; Taking a read lock should be OK.
|
||||||
|
(fcntl-flock file 'read-lock)
|
||||||
|
(fcntl-flock file 'unlock)
|
||||||
|
|
||||||
|
(catch 'flock-error
|
||||||
|
(lambda ()
|
||||||
|
;; Taking an exclusive lock should raise an exception.
|
||||||
|
(fcntl-flock file 'write-lock))
|
||||||
|
(lambda args
|
||||||
|
(primitive-exit 0)))
|
||||||
|
(primitive-exit 1))
|
||||||
|
(lambda ()
|
||||||
|
(primitive-exit 2))))
|
||||||
|
(pid
|
||||||
|
(match (waitpid pid)
|
||||||
|
((_ . status)
|
||||||
|
(let ((result (status:exit-val status)))
|
||||||
|
(fcntl-flock file 'unlock)
|
||||||
|
(close-port file)
|
||||||
|
result)))))))
|
||||||
|
|
||||||
;; This is actually in (guix store).
|
;; This is actually in (guix store).
|
||||||
(test-equal "store-path-package-name"
|
(test-equal "store-path-package-name"
|
||||||
"bash-4.2-p24"
|
"bash-4.2-p24"
|
||||||
|
|
Loading…
Reference in New Issue