From: Artem Baguinski
Subject: CMUCL alien function parameters
Date: 
Message-ID: <87znb5onqb.fsf@caracolito.lan>
hi

how come the follwing:

(alien-funcall
 (extern-alien
  "wrap_read_packet"
  (function 
   av-error 
   (* t)
   (* t)))
 nil nil)

works and

the following:

(alien-funcall
 (extern-alien
  "wrap_read_packet"
  (function 
   av-error 
   (* t) 
   (* (struct packet)))) ;; <-- the only difference
 nil nil)

acts like it's entering some evil endless recursion:

; Compiling LAMBDA (#:G1031 #:G1032 #:G1033): 
; [GC threshold exceeded with 12,015,528 bytes in use.  Commencing GC.]
; [GC completed with 6,225,856 bytes retained and 5,789,672 bytes freed.]
; [GC will next occur when at least 18,225,856 bytes are in use.]
; [GC threshold exceeded with 18,234,240 bytes in use.  Commencing GC.]
; [GC completed with 18,234,248 bytes retained and -8 bytes freed.]
; [GC will next occur when at least 30,234,248 bytes are in use.]
; [GC threshold exceeded with 30,243,712 bytes in use.  Commencing GC.]
; [GC completed with 30,245,640 bytes retained and -1,928 bytes freed.]
; [GC will next occur when at least 42,245,640 bytes are in use.]
; [GC threshold exceeded with 42,255,104 bytes in use.  Commencing GC.]
; [GC completed with 42,255,112 bytes retained and -8 bytes freed.]
; [GC will next occur when at least 54,255,112 bytes are in use.]

and dies somewhere here.

the struct packet is:

(def-alien-type av-packet
  (struct packet
	  (:pts (integer 64))
	  (:data (* unsigned-char))
	  (:size int)
	  (:stream-index int)
	  (:flags int)
	  (:duration int)
	  (:destruct (* (function void (* (struct packet)))))
	  (:priv (* t))))


thanks

-- 
gr{oe|ee}t{en|ings}
artm 
From: Helmut Eller
Subject: Re: CMUCL alien function parameters
Date: 
Message-ID: <m23c8w5mtn.fsf@62.178.77.205>
Artem Baguinski <····@v2.nl> writes:
Artem Baguinski <····@v2.nl> writes:

> 
> hi
> 
> how come the follwing:
[snip]
> acts like it's entering some evil endless recursion:
[snip]
> and dies somewhere here.
> 
> the struct packet is:
> 
> (def-alien-type av-packet
>   (struct packet
> 	  (:pts (integer 64))
> 	  (:data (* unsigned-char))
> 	  (:size int)
> 	  (:stream-index int)
> 	  (:flags int)
> 	  (:duration int)
> 	  (:destruct (* (function void (* (struct packet)))))
> 	  (:priv (* t))))

It's a bug.  I use the patch below to fix it.

Helmut.


;;; Fix a bug in alien::record-fields-match involving recursive alien
;;; records with functions pointers.  The original version recursed
;;; endlessly for function pointers with the to be defined record
;;; type as argument.

#|					
Testcase:

;;; this cannot be compiled twice 

(def-alien-type nil (struct foo
			    (f (* (function (values) (* (struct foo)))))))

 
|#

(in-package :alien)

(defun record-fields-match (fields1 fields2)
  (loop for field1 in fields1
	for field2 in fields2
	always (and (eq (alien-record-field-name field1)
			(alien-record-field-name field2))
		    (eql (alien-record-field-bits field1)
			 (alien-record-field-bits field2))
		    (eql (alien-record-field-offset field1)
			 (alien-record-field-offset field2))
		    (alien-type-= (alien-record-field-type field1)
				  (alien-record-field-type field2)))))

(defvar *match-history* nil)
(defvar *the-match-cache* (make-hash-table :test #'eq))

(declaim (inline in-match-history-or))
(defun in-match-history-or (type1 type2 alternative)
  (cond (*match-history*
	 (let ((list (gethash type1 *match-history*)))
	   (cond ((memq type2 list)
		  t)
		 (t 
		  (setf (gethash type1 *match-history*) (cons type2 list))
		  (funcall alternative)))))
	(t
	 (let ((*match-history* (progn (clrhash *the-match-cache*)
				       *the-match-cache*)))
	   (setf (gethash type1 *match-history*) (list type2))
	   (funcall alternative)))))

(def-alien-type-method (record :type=) (type1 type2)
  (and (eq (alien-record-type-name type1) 
	   (alien-record-type-name type2))
       (eq (alien-record-type-kind type1) 
	   (alien-record-type-kind type2))
       (eql (alien-type-bits type1) 
	    (alien-type-bits type2))
       (eql (alien-type-alignment type1) 
	    (alien-type-alignment type2))
       (= (length (alien-record-type-fields type1))
	  (length (alien-record-type-fields type2)))
       (in-match-history-or 
	type1 type2
	(lambda ()
	  (record-fields-match 
	   (alien-record-type-fields type1)
	   (alien-record-type-fields type2))))))


#+(or) 
;; list based version. to slow for large type hirarchies,
;; e.g. gtk.
(def-alien-type-method (record :type=) (type1 type2)
  (and (eq (alien-record-type-name type1)
	   (alien-record-type-name type2))
       (eq (alien-record-type-kind type1) 
	   (alien-record-type-kind type2))
       (= (length (alien-record-type-fields type1))
	  (length (alien-record-type-fields type2)))
       (let ((pair (cons type1 type2)))
	 (or (member pair *match-history* :test #'equal)
	     (let ((*match-history* (cons pair *match-history*)))
	       ;;(format t "~&length = ~D~%" (length *match-history*))
	       (record-fields-match 
		(alien-record-type-fields type1)
		(alien-record-type-fields type2)))))))