summary refs log tree commit diff
diff options
context:
space:
mode:
authorLudovic Courtès <ludo@gnu.org>2016-04-25 16:47:23 +0200
committerLudovic Courtès <ludo@gnu.org>2016-04-25 23:27:09 +0200
commit785cfa8791b0d683830245f119ee6fd42e5356d3 (patch)
tree5b6046a7d3b2e488b3dc3a5bfe2f780a494309e7
parentf77863a09eebf65299e734d27f1c5b96e9742f52 (diff)
downloadguix-785cfa8791b0d683830245f119ee6fd42e5356d3.tar.gz
syscalls: 'define-c-struct' computes the struct size.
* guix/build/syscalls.scm (struct-alignment, struct-size): New macros.
(define-c-struct): Add 'size' parameter and honor it.
(sockaddr-in, sockaddr-in6, ifaddrs, winsize): Adjust accordingly.
(%struct-ifaddrs-type, %sizeof-ifaddrs, winsize-struct): Remove.
(terminal-window-size): Use 'make-bytevector' instead of 'make-c-struct'.
-rw-r--r--guix/build/syscalls.scm52
1 files changed, 35 insertions, 17 deletions
diff --git a/guix/build/syscalls.scm b/guix/build/syscalls.scm
index 7c32e25971..468dc7eca2 100644
--- a/guix/build/syscalls.scm
+++ b/guix/build/syscalls.scm
@@ -145,6 +145,27 @@
     ((_ type)
      (sizeof* type))))
 
+(define-syntax struct-alignment
+  (syntax-rules ()
+    "Compute the alignment for the aggregate made of TYPES at OFFSET.  The
+result is the alignment of the \"most strictly aligned component\"."
+    ((_ offset types ...)
+     (max (align offset types) ...))))
+
+(define-syntax struct-size
+  (syntax-rules ()
+    "Return the size in bytes of the structure made of TYPES."
+    ((_ offset (types-processed ...))
+     ;; The SysV ABI P.S. says: "Aggregates (structures and arrays) and unions
+     ;; assume the alignment of their most strictly aligned component."  As an
+     ;; example, a struct such as "int32, int16" has size 8, not 6.
+     (1+ (logior (1- offset)
+                 (1- (struct-alignment offset types-processed ...)))))
+    ((_ offset (types-processed ...) type0 types ...)
+     (struct-size (+ (type-size type0) (align offset type0))
+                  (type0 types-processed ...)
+                  types ...))))
+
 (define-syntax write-type
   (syntax-rules (~)
     ((_ bv offset (type ~ order) value)
@@ -193,10 +214,13 @@
 
 (define-syntax define-c-struct
   (syntax-rules ()
-    "Define READ as a deserializer and WRITE! as a serializer for the C
-structure with the given TYPES.  READ uses WRAP-FIELDS to return its value."
-    ((_ name wrap-fields read write! (fields types) ...)
+    "Define SIZE as the size in bytes of the C structure made of FIELDS.  READ
+as a deserializer and WRITE! as a serializer for the C structure with the
+given TYPES.  READ uses WRAP-FIELDS to return its value."
+    ((_ name size wrap-fields read write! (fields types) ...)
      (begin
+       (define size
+         (struct-size 0 () types ...))
        (define (write! bv offset fields ...)
          (write-types bv offset (types ...) (fields ...)))
        (define* (read bv #:optional (offset 0))
@@ -559,6 +583,7 @@ system to PUT-OLD."
       32))
 
 (define-c-struct sockaddr-in                      ;<linux/in.h>
+  sizeof-sockaddrin
   (lambda (family port address)
     (make-socket-address family address port))
   read-sockaddr-in
@@ -568,6 +593,7 @@ system to PUT-OLD."
   (address   (int32 ~ big)))
 
 (define-c-struct sockaddr-in6                     ;<linux/in6.h>
+  sizeof-sockaddr-in6
   (lambda (family port flowinfo address scopeid)
     (make-socket-address family address port flowinfo scopeid))
   read-sockaddr-in6
@@ -832,6 +858,7 @@ an <interface> object, and whose cdr is the pointer NEXT."
         next))
 
 (define-c-struct ifaddrs                          ;<ifaddrs.h>
+  %sizeof-ifaddrs
   values->interface
   read-ifaddrs
   write-ifaddrs!
@@ -843,14 +870,6 @@ an <interface> object, and whose cdr is the pointer NEXT."
   (broadcastaddr '*)
   (data          '*))
 
-(define-syntax %struct-ifaddrs-type
-  (identifier-syntax
-   `(* * ,unsigned-int * * * *)))
-
-(define-syntax %sizeof-ifaddrs
-  (identifier-syntax
-   (sizeof* %struct-ifaddrs-type)))
-
 (define (unfold-interface-list ptr)
   "Call 'read-ifaddrs' on PTR and all its 'next' fields, recursively, and
 return the list of resulting <interface> objects."
@@ -901,6 +920,7 @@ network interface.  This is implemented using the 'getifaddrs' libc function."
   (y-pixels window-size-y-pixels))
 
 (define-c-struct winsize                          ;<bits/ioctl-types.h>
+  sizeof-winsize
   window-size
   read-winsize
   write-winsize!
@@ -909,18 +929,16 @@ network interface.  This is implemented using the 'getifaddrs' libc function."
   (x-pixels      unsigned-short)
   (y-pixels      unsigned-short))
 
-(define winsize-struct
-  (list unsigned-short unsigned-short unsigned-short unsigned-short))
-
 (define* (terminal-window-size #:optional (port (current-output-port)))
   "Return a <window-size> structure describing the terminal at PORT, or raise
 a 'system-error' if PORT is not backed by a terminal.  This procedure
 corresponds to the TIOCGWINSZ ioctl."
-  (let* ((size (make-c-struct winsize-struct '(0 0 0 0)))
-         (ret  (%ioctl (fileno port) TIOCGWINSZ size))
+  (let* ((size (make-bytevector sizeof-winsize))
+         (ret  (%ioctl (fileno port) TIOCGWINSZ
+                       (bytevector->pointer size)))
          (err  (errno)))
     (if (zero? ret)
-        (read-winsize (pointer->bytevector size (sizeof winsize-struct)))
+        (read-winsize size)
         (throw 'system-error "terminal-window-size" "~A"
                (list (strerror err))
                (list err)))))