1 2;; Externally, a cpointer can be #f or a byte string, in 3;; addition to a cpointer record 4(define (cpointer? v) 5 (or (authentic-cpointer? v) 6 (not v) 7 (bytes? v) 8 (has-cpointer-property? v))) 9 10;; A cpointer record's `memory` is either a raw foreign address (i.e., a 11;; number), bytevector, or flvector. A reference bytevector is used for 12;; non-atomic memory. 13(define-record-type (cpointer make-cpointer authentic-cpointer?) 14 (fields memory (mutable tags))) 15(define-record-type cpointer+offset 16 (parent cpointer) 17 (fields (mutable offset))) 18 19(define-values (prop:cpointer has-cpointer-property? cpointer-property-ref) 20 (make-struct-type-property 'cpointer 21 (lambda (v info) 22 (cond 23 [(exact-nonnegative-integer? v) 24 (unless (< v (list-ref info 1)) 25 (raise-arguments-error 'prop:cpointer 26 "index is out of range" 27 "index" v)) 28 (unless (#%memv v (list-ref info 5)) 29 (raise-arguments-error 'prop:cpointer 30 "index does not refer to an immutable field" 31 "index" v)) 32 (+ v (let ([p (list-ref info 6)]) 33 (if p 34 (struct-type-total*-field-count p) 35 0)))] 36 [(and (procedure? v) 37 (procedure-arity-includes? v 1)) 38 v] 39 [(cpointer? v) v] 40 [else 41 (raise-argument-error 'prop:cpointer 42 (string-append 43 "(or/c exact-nonnegative-integer?\n" 44 " (procedure-arity-includes/c 1)\n" 45 " cpointer?)") 46 v)])))) 47 48;; Gets a primitive cpointer type by following a `prop:evt` property 49;; as needed. Call with function *before* disabling GC interrupts. 50(define (unwrap-cpointer who p) 51 (cond 52 [(authentic-cpointer? p) p] 53 [(not p) p] 54 [(bytes? p) p] 55 [(ffi-callback? p) p] 56 [else (let ([v (cpointer-property-ref p)]) 57 (cond 58 [(exact-nonnegative-integer? v) 59 (let ([v (unsafe-struct-ref p v)]) 60 (if (cpointer? v) 61 (unwrap-cpointer who v) 62 #f))] 63 [(procedure? v) 64 (let ([p2 (v p)]) 65 (unless (cpointer? p2) 66 (raise-result-error 'prop:cpointer-accessor 67 "cpointer?" 68 p2)) 69 (unwrap-cpointer who p2))] 70 [else 71 (unwrap-cpointer who v)]))])) 72 73;; Like `unwrap-cpointer*`, but also allows an integer as a raw 74;; foreign address: 75(define (unwrap-cpointer* who p) 76 (if (integer? p) 77 p 78 (unwrap-cpointer who p))) 79 80(define (offset-ptr? p) 81 (unless (cpointer? p) 82 (raise-argument-error 'offset-ptr? "cpointer?" p)) 83 (cpointer+offset? p)) 84 85(define/who (set-cpointer-tag! p t) 86 (if (authentic-cpointer? p) 87 (cpointer-tags-set! p t) 88 (if (cpointer? p) 89 (let ([q (unwrap-cpointer who p)]) 90 (if (authentic-cpointer? q) 91 (set-cpointer-tag! q t) 92 (raise-arguments-error who 93 "cannot set tag on given cpointer" 94 "given" p 95 "tag" t))) 96 (raise-argument-error who "cpointer?" p)))) 97 98(define/who (cpointer-tag p) 99 (if (authentic-cpointer? p) 100 (cpointer-tags p) 101 (if (cpointer? p) 102 (let ([q (unwrap-cpointer who p)]) 103 (if (authentic-cpointer? q) 104 (cpointer-tag q) 105 #f)) 106 (raise-argument-error who "cpointer?" p)))) 107 108;; Convert a `memory` --- typically a raw foreign address, but possibly 109;; a bytevector or flvector --- to a cpointer, using #f for a NULL 110;; address: 111(define (memory->cpointer x) 112 (cond 113 [(or (not x) (authentic-cpointer? x)) 114 ;; This happens when a pointer is converted without going through 115 ;; `cpointer-address` such as a `ptr-ref` on a struct or array type 116 x] 117 [(eqv? x 0) #f] 118 [else (make-cpointer x #f)])) 119 120;; Works on unwrapped cpointers: 121(define (cpointer-nonatomic? p) 122 (and (authentic-cpointer? p) 123 (reference-bytevector? (cpointer-memory p)))) 124 125;; Works on unwrapped cpointers: 126(define (cpointer->name proc-p) 127 (and (ffi-obj? proc-p) 128 (string->symbol (utf8->string (cpointer/ffi-obj-name proc-p))))) 129 130;; ---------------------------------------- 131 132;; Convert a raw foreign address to a Scheme value on the 133;; assumption that the address is the payload of a byte 134;; string: 135(define (addr->gcpointer-memory v) ; call with GC disabled 136 (reference-address->object v)) 137 138;; Converts a primitive cpointer (normally the result of 139;; `unwrap-cpointer`) to a memory plus offset 140(define (cpointer-address+offset p) 141 (cond 142 [(not p) (values 0 0)] 143 [(or (bytevector? p) (flvector? p)) (values p 0)] 144 [(cpointer+offset? p) 145 (values (cpointer-memory p) (cpointer+offset-offset p))] 146 [(authentic-cpointer? p) 147 (values (cpointer-memory p) 0)] 148 [(ffi-callback? p) 149 (values (foreign-callable-entry-point (callback-code p)) 0)] 150 [else 151 (raise-arguments-error 'internal-error "bad case extracting a cpointer address" 152 "value" p)])) 153 154;; Convert a `memory` (as in a cpointer) to a raw foreign address. 155(define (memory-address memory) ; call with GC disabled 156 (cond 157 [(integer? memory) memory] 158 [else (object->reference-address memory)])) 159 160;; Converts a primitive cpointer (normally the result of 161;; `unwrap-cpointer`) to a raw foreign address. The 162;; GC must be disabled while extracting an address, 163;; which might be the address of a byte string that 164;; could otherwise change due to a GC. 165(define (cpointer-address p) ; call with GC disabled 166 (let-values ([(memory offset) (cpointer-address+offset p)]) 167 (+ (memory-address memory) offset))) 168 169(define (cpointer-needs-lock? p) 170 (cond 171 [(bytes? p) #t] 172 [(authentic-cpointer? p) (not (integer? (cpointer-memory p)))] 173 [else #f])) 174 175;; Like `cpointer-address`, but allows a raw foreign 176;; address to pass through: 177(define (cpointer*-address p) ; call with GC disabled 178 (if (number? p) 179 p 180 (cpointer-address p))) 181 182;; ---------------------------------------- 183 184(define/who (ptr-equal? p1 p2) 185 (let ([p1 (unwrap-cpointer who p1)] 186 [p2 (unwrap-cpointer who p2)]) 187 (with-interrupts-disabled* ; disable GC while extracting addresses 188 (= (cpointer-address p1) (cpointer-address p2))))) 189 190(define/who (ptr-offset p) 191 (let ([p (unwrap-cpointer who p)]) 192 (ptr-offset* p))) 193 194(define (ptr-offset* p) 195 (if (cpointer+offset? p) 196 (cpointer+offset-offset p) 197 0)) 198 199(define (set-ptr-offset! p n) 200 (unless (cpointer+offset? p) 201 (raise-argument-error 'ptr-offset "(and/c cpointer? ptr-offset?)" p)) 202 (unless (exact-integer? n) 203 (raise-argument-error 'ptr-offset "exact-integer?" n)) 204 (cpointer+offset-offset-set! p n)) 205 206(define ptr-add 207 (case-lambda 208 [(p n type) 209 (unless (cpointer? p) 210 (raise-argument-error 'ptr-add "cpointer?" p)) 211 (unless (exact-integer? n) 212 (raise-argument-error 'ptr-add "exact-integer?" n)) 213 (unless (ctype? type) 214 (raise-argument-error 'ptr-add "ctype?" type)) 215 (do-ptr-add p (* n (ctype-sizeof type)) #t)] 216 [(p n) 217 (unless (cpointer? p) 218 (raise-argument-error 'ptr-add "cpointer?" p)) 219 (unless (exact-integer? n) 220 (raise-argument-error 'ptr-add "exact-integer?" n)) 221 (do-ptr-add p n #t)])) 222 223(define (do-ptr-add p n save-tags?) 224 (cond 225 [(authentic-cpointer? p) 226 (make-cpointer+offset (cpointer-memory p) 227 (and save-tags? (cpointer-tag p)) 228 (+ n (ptr-offset* p)))] 229 [(has-cpointer-property? p) 230 (do-ptr-add (unwrap-cpointer 'do-ptr-add p) n save-tags?)] 231 [else 232 (make-cpointer+offset (or p 0) #f n)])) 233 234(define ptr-add! 235 (case-lambda 236 [(p n type) 237 (unless (cpointer+offset? p) 238 (raise-argument-error 'ptr-add! "(and/c cpointer? offset-ptr?)" p)) 239 (unless (exact-integer? n) 240 (raise-argument-error 'ptr-add! "exact-integer?" n)) 241 (unless (ctype? type) 242 (raise-argument-error 'ptr-add! "ctype?" type)) 243 (do-ptr-add! p (* n (ctype-sizeof type)))] 244 [(p n) 245 (unless (cpointer+offset? p) 246 (raise-argument-error 'ptr-add! "(and/c cpointer? offset-ptr?)" p)) 247 (unless (exact-integer? n) 248 (raise-argument-error 'ptr-add! "exact-integer?" n)) 249 (do-ptr-add! p n)])) 250 251(define (do-ptr-add! p n) 252 (unless (cpointer+offset? p) 253 (raise-arguments-error 'ptr-add! 254 "given cpointer does not have an offset" 255 "given" p)) 256 (cpointer+offset-offset-set! p (+ n (cpointer+offset-offset p)))) 257 258;; ---------------------------------------- 259 260;; In ctype-host-rep, we use 'uptr and 'void* (which are aliases for foreign-ref) 261;; to reflect intent with respect to foreign versus Scheme addresses when reading: 262;; - 'uptr => inferred as Scheme or foreign, read as memory instead of address 263;; - 'void* => ctype-out-rep ('pointer versus 'gcpointer) implies Scheme or foreign, 264;;; and ctype-out-rep is assumed to be correct in that regard 265 266(define-record-type (ctype create-ctype ctype?) 267 (fields host-rep ; host-Scheme representation description, 'struct, 'union, or 'array 268 our-rep ; Racket representation description 269 basetype ; parent ctype or the same as `our-rep` 270 scheme->c ; converter of values to `basetype` 271 c->scheme)) ; converter of values from `basetype` 272 273;; A `compound-ctype` is used for structs, unions, and arrays 274(define-record-type (compound-ctype create-compound-ctype compound-ctype?) 275 (parent ctype) 276 (fields get-decls 277 size 278 alignment 279 malloc-mode)) 280 281(define/who (make-ctype type racket-to-c c-to-racket) 282 (check who ctype? type) 283 (check who (procedure-arity-includes/c 1) :or-false racket-to-c) 284 (check who (procedure-arity-includes/c 1) :or-false c-to-racket) 285 (cond 286 [(compound-ctype? type) 287 (create-compound-ctype (ctype-host-rep type) 288 (ctype-our-rep type) 289 type 290 (protect-racket-to-c racket-to-c) 291 c-to-racket 292 (compound-ctype-get-decls type) 293 (compound-ctype-size type) 294 (compound-ctype-alignment type) 295 (compound-ctype-malloc-mode type))] 296 [else 297 (create-ctype (ctype-host-rep type) 298 (ctype-our-rep type) 299 type 300 (protect-racket-to-c racket-to-c) 301 c-to-racket)])) 302 303(define (protect-racket-to-c racket-to-c) 304 ;; Make sure `racket-to-c` is not confused for an internal 305 ;; variant that accepts a `who` argument: 306 (if (and (#%procedure? racket-to-c) 307 (chez:procedure-arity-includes? racket-to-c 2)) 308 (lambda (v) (racket-to-c v)) 309 racket-to-c)) 310 311;; Apply all the conversion wrappers of `type` to the Scheme value `v` 312(define (s->c who type v) 313 (let* ([racket-to-c (ctype-scheme->c type)] 314 [v (if racket-to-c 315 (if (and (#%procedure? racket-to-c) 316 (chez:procedure-arity-includes? racket-to-c 2)) 317 (racket-to-c who v) 318 (|#%app| racket-to-c v)) 319 v)] 320 [next (ctype-basetype type)]) 321 (if (ctype? next) 322 (s->c who next v) 323 v))) 324 325;; Apply all the conversion wrapper of `type` to the C value `v` 326(define (c->s type v) 327 (let* ([next (ctype-basetype type)] 328 [v (if (ctype? next) 329 (c->s next v) 330 v)] 331 [c-to-racket (ctype-c->scheme type)]) 332 (if c-to-racket 333 (|#%app| c-to-racket v) 334 v))) 335 336;; ---------------------------------------- 337 338(define-syntax define-ctype 339 (syntax-rules () 340 [(_ id host-rep basetype) 341 (define/who id (create-ctype host-rep basetype basetype #f #f))] 342 [(_ id host-rep basetype s->c) 343 (define/who id (create-ctype host-rep basetype basetype s->c #f))] 344 [(_ id host-rep basetype s->c c->s) 345 (define/who id (create-ctype host-rep basetype basetype s->c c->s))])) 346 347;; We need `s->c` checks, even if they seem redundant, to make sure 348;; that the checks happen early enough --- outside of atomic and 349;; foreign-thread regions. Also, the integer checks built into Chez 350;; Scheme are more permissive than Racket's. 351 352(define-syntax-rule (checker who ?) (lambda (for-whom x) (if (? x) x (bad-ctype-value for-whom who x)))) 353(define-syntax integer-checker 354 (syntax-rules (signed unsigned) 355 [(_ who signed n int?) (checker who (lambda (x) (and (int? x) (<= (- (expt 2 (- n 1))) x (- (expt 2 (- n 1)) 1)))))] 356 [(_ who unsigned n int?) (checker who (lambda (x) (and (int? x) (<= 0 x (- (expt 2 n) 1)))))])) 357 358(define-ctype _bool 'boolean 'bool) 359(define-ctype _double 'double 'double (checker who flonum?)) 360(define-ctype _fixnum 'fixnum 'fixnum (checker who fixnum?)) 361(define-ctype _float 'float 'float (checker who flonum?)) 362(define-ctype _int8 'integer-8 'int8 (integer-checker who signed 8 fixnum?)) 363(define-ctype _int16 'integer-16 'int16 (integer-checker who signed 16 fixnum?)) 364(define-ctype _int32 'integer-32 'int32 (integer-checker who signed 32 exact-integer?)) 365(define-ctype _int64 'integer-64 'int64 (integer-checker who signed 64 exact-integer?)) 366(define-ctype _uint8 'unsigned-8 'uint8 (integer-checker who unsigned 8 fixnum?)) 367(define-ctype _uint16 'unsigned-16 'uint16 (integer-checker who unsigned 16 fixnum?)) 368(define-ctype _uint32 'unsigned-32 'uint32 (integer-checker who unsigned 32 exact-integer?)) 369(define-ctype _uint64 'unsigned-64 'uint64 (integer-checker who unsigned 64 exact-integer?)) 370(define-ctype _scheme 'scheme-object 'scheme) 371(define-ctype _void 'void 'void (checker who void)) 372 373(define (bad-ctype-value who type-name v) 374 (raise-arguments-error who 375 "given value does not fit primitive C type" 376 "C type" (make-unquoted-printing-string (symbol->string type-name)) 377 "value" v)) 378 379;; Unlike traditional Racket, copies when converting from C: 380(define-ctype _bytes 'uptr 'bytes 381 (checker who (lambda (x) (or (not x) (bytes? x)))) 382 (lambda (x) 383 (cond 384 [(not x) ; happens with non-atomic memory reference 385 x] 386 [(bytes? x) ; happens with non-atomic memory reference 387 ;; For consistency, truncate byte string at any NUL byte 388 (let ([len (bytes-length x)]) 389 (let loop ([i 0]) 390 (cond 391 [(fx= i len) x] 392 [(fx= 0 (bytes-ref x i)) 393 (subbytes x 0 i)] 394 [else (loop (fx+ i 1))])))] 395 [(eqv? x 0) #f] 396 [else 397 (let loop ([i 0]) 398 (if (fx= 0 (foreign-ref 'unsigned-8 x i)) 399 (let ([bstr (make-bytes i)]) 400 (memcpy* bstr 0 x 0 i #f) 401 bstr) 402 (loop (fx+ i 1))))]))) 403 404(define (uptr->bytevector/two-nuls x) 405 (cond 406 [(not x) #f] 407 [else 408 (let loop ([i 0]) 409 (if (fx= 0 (if (bytevector? x) 410 (bytevector-u16-native-ref x i) 411 (foreign-ref 'unsigned-16 x i))) 412 (let ([bstr (make-bytes i)]) 413 (memcpy* bstr 0 x 0 i #f) 414 bstr) 415 (loop (+ i 2))))])) 416 417(define-ctype _short_bytes 'uptr 'bytes 418 (lambda (form-whom x) x) 419 (lambda (x) (uptr->bytevector/two-nuls x))) 420 421(define-ctype _string/utf-16 'uptr 'string/utf-16 422 (lambda (for-whom x) 423 (cond 424 [(not x) #f] 425 [(string? x) (string->utf16 (string-append x "\x0;") (if (system-big-endian?) 'big 'little))] 426 [else (bad-ctype-value who for-whom x)])) 427 (lambda (x) (and x 428 (not (eq? x 0)) 429 (utf16->string (uptr->bytevector/two-nuls x) 430 (if (system-big-endian?) 'big 'little))))) 431 432(define (uptr->bytevector/four-nuls x) 433 (cond 434 [(not x) #f] 435 [else 436 (let loop ([i 0]) 437 (if (eqv? 0 (if (bytevector? x) 438 (bytevector-u32-native-ref x i) 439 (foreign-ref 'unsigned-32 x i))) 440 (let ([bstr (make-bytes i)]) 441 (memcpy* bstr 0 x 0 i #f) 442 bstr) 443 (loop (+ i 4))))])) 444 445(define-ctype _string/ucs-4 'uptr 'string/ucs-4 446 (lambda (for-whom x) 447 (cond 448 [(not x) #f] 449 [(string? x) (string->utf32 (string-append x "\x0;") (if (system-big-endian?) 'big 'little))] 450 [else (bad-ctype-value who for-whom x)])) 451 (lambda (x) (and x 452 (not (eq? x 0)) 453 (utf32->string (uptr->bytevector/four-nuls x) 454 (if (system-big-endian?) 'big 'little))))) 455 456(define-ctype _double* 'double 'double 457 (lambda (for-whom x) (if (real? x) 458 (exact->inexact x) 459 (bad-ctype-value for-whom who x)))) 460 461(define-ctype _ufixnum 'fixnum 'fixnum (checker who fixnum?)) ; historically, no sign check 462(define-ctype _fixint 'integer-32 'fixint (checker who fixnum?)) 463(define-ctype _ufixint 'unsigned-32 'ufixint (checker who fixnum?)) ; historically, no sign check 464 465(define-ctype _symbol 'string 'string 466 (lambda (for-whom x) (if (symbol? x) 467 (symbol->string x) 468 (bad-ctype-value for-whom who x))) 469 (lambda (s) (string->symbol s))) 470 471(define-ctype _longdouble 'double 'double 472 (lambda (for-whom x) (bad-ctype-value for-whom who x))) 473 474(define-ctype _pointer 'void* 'pointer 475 (lambda (for-whom v) (unwrap-cpointer for-whom v)) ; resolved to an address later (with the GC disabled) 476 (lambda (x) (memory->cpointer x))) 477 478;; Treated specially by `ptr-ref` 479(define-ctype _fpointer 'void* 'fpointer 480 (lambda (for-whom v) (unwrap-cpointer for-whom v)) ; resolved to an address later (with the GC disabled) 481 (lambda (x) 482 (if (ffi-obj? x) ; check for `ptr-ref` special case on `ffi-obj`s 483 x 484 (memory->cpointer x)))) 485 486(define-ctype _gcpointer 'void* 'gcpointer 487 (lambda (for-whom v) (unwrap-cpointer for-whom v)) ; like `_pointer`: resolved later 488 (lambda (x) 489 ;; `x` must have been converted to a bytevector or vector before 490 ;; the GC was re-enabled 491 (memory->cpointer x))) 492 493;; One-byte stdbool is correct on all currently supported platforms, at least: 494(define-ctype _stdbool 'integer-8 'stdbool 495 (lambda (for-whom x) (if x 1 0)) 496 (lambda (v) (not (zero? v)))) 497 498(define make-cstruct-type 499 (case-lambda 500 [(types) (make-cstruct-type types #f #f 'atomic)] 501 [(types abi) (make-cstruct-type types abi #f 'atomic)] 502 [(types abi alignment) (make-cstruct-type types abi alignment 'atomic)] 503 [(types abi alignment malloc-mode) 504 (let ([make-decls 505 (lambda (id next!-id) 506 (let-values ([(reps decls) (types->reps types next!-id)]) 507 (append decls 508 `((define-ftype ,id 509 (struct ,@(map (lambda (rep) 510 `[,(next!-id) ,rep]) 511 reps)))))))]) 512 (let-values ([(size alignment) (ctypes-sizeof+alignof types alignment)]) 513 (create-compound-ctype 'struct 514 'struct 515 types 516 (lambda (s) (unwrap-cpointer '_struct s)) ; like `_pointer`: resolved later 517 (lambda (c) (memory->cpointer c)) 518 make-decls 519 size 520 alignment 521 malloc-mode)))])) 522 523(define/who (make-union-type . types) 524 (for-each (lambda (type) (check who ctype? type)) 525 types) 526 (let ([make-decls 527 (lambda (id next!-id) 528 (let-values ([(reps decls) (types->reps types next!-id)]) 529 (append decls 530 `((define-ftype ,id 531 (union ,@(map (lambda (rep) 532 `[,(next!-id) ,rep]) 533 reps)))))))] 534 [size (apply max (map ctype-sizeof types))] 535 [alignment (apply max (map ctype-alignof types))]) 536 (create-compound-ctype 'union 537 'union 538 types 539 (lambda (s) (unwrap-cpointer '_union s)) ; like `_pointer`: resolved later 540 (lambda (c) (memory->cpointer c)) 541 make-decls 542 size 543 alignment 544 'atomic))) 545 546(define/who (make-array-type type count) 547 (check who ctype? type) 548 (check who exact-nonnegative-integer? count) 549 (let ([make-decls 550 (lambda (id next!-id) 551 (let-values ([(reps decls) (types->reps (list type) next!-id)]) 552 (append decls 553 `((define-ftype ,id 554 (array ,count ,(car reps)))))))] 555 [size (* count (ctype-sizeof type))] 556 [alignment (ctype-alignof type)]) 557 (unless (fixnum? size) 558 (raise-arguments-error who "arithmetic overflow for overlarge array type" 559 "size" size)) 560 (create-compound-ctype 'array 561 'array 562 (vector type count) 563 (lambda (s) (unwrap-cpointer '_array s)) ; like `_pointer`: resolved later 564 (lambda (c) (memory->cpointer c)) 565 make-decls 566 size 567 alignment 568 #f))) 569 570(define (compiler-sizeof sl) 571 (let ([rest (lambda (sl) (if (pair? sl) (cdr sl) '()))]) 572 (unless (or (symbol? sl) 573 (list? sl)) 574 (raise-argument-error 'compiler-sizeof 575 "(or/c ctype-symbol? (listof ctype-symbol?))" 576 sl)) 577 (let loop ([sl sl] [base-type #f] [star? #f] [size #f]) 578 (cond 579 [(null? sl) 580 (cond 581 [(eq? base-type 'void) 582 (when size 583 (raise-arguments-error 'compiler-sizeof "cannot qualify 'void")) 584 (if star? 585 (foreign-sizeof 'void*) 586 (raise-arguments-error 'compiler-sizeof "cannot use 'void without a '*"))] 587 [(or (not size) 588 (eq? base-type 'int) 589 (not base-type)) 590 (if star? 591 (foreign-sizeof 'void*) 592 (foreign-sizeof (or size base-type 'int)))] 593 [(eq? base-type 'double) 594 (case size 595 [(long) 596 (if star? 597 (foreign-sizeof 'void*) 598 ;; FIXME: 599 (foreign-sizeof 'double))] 600 [(#f) 601 (if star? 602 (foreign-sizeof 'void*) 603 (foreign-sizeof 'double))] 604 [else 605 (raise-arguments-error 'compiler-sizeof "bad qualifiers for 'double")])] 606 [(eq? base-type 'float) 607 (case size 608 [(#f) 609 (if star? 610 (foreign-sizeof 'void*) 611 (foreign-sizeof 'float))] 612 [else 613 (raise-arguments-error 'compiler-sizeof "bad qualifiers for 'float")])] 614 [size 615 (raise-arguments-error 'compiler-sizeof (format "cannot qualify '~a" base-type))])] 616 [else 617 (let ([s (if (pair? sl) (car sl) sl)]) 618 (case s 619 [(int char wchar float double void) 620 (cond 621 [base-type 622 (raise-arguments-error 'compiler-sizeof 623 (format "extraneous type: '~a" s))] 624 [else 625 (loop (rest sl) s star? size)])] 626 [(short) 627 (case size 628 [(short) 629 (raise-arguments-error 'compiler-sizeof 630 "cannot handle more than one 'short")] 631 [(long) 632 (raise-arguments-error 'compiler-sizeof 633 "cannot use both 'short and 'long")] 634 [(#f) (loop (rest sl) base-type star? 'short)])] 635 [(long) 636 (case size 637 [(short) 638 (raise-arguments-error 'compiler-sizeof 639 "cannot use both 'short and 'long")] 640 [(long-long) 641 (raise-arguments-error 'compiler-sizeof 642 "cannot handle more than two 'long")] 643 [(long) 644 (loop (rest sl) base-type star? 'long-long)] 645 [(#f) 646 (loop (rest sl) base-type star? 'long)])] 647 [(*) 648 (if star? 649 (raise-arguments-error 'compiler-sizeof 650 "cannot handle more than one '*") 651 (loop (rest sl) base-type #t size))] 652 [else 653 (raise-argument-error 'compiler-sizeof 654 "(or/c ctype-symbol? (listof ctype-symbol?))" 655 sl)]))])))) 656 657(define (ctype-malloc-mode c) 658 (let ([t (ctype-our-rep c)]) 659 (if (or (eq? t 'gcpointer) 660 (eq? t 'bytes) 661 (eq? t 'scheme) 662 (eq? t 'string) 663 (eq? t 'string/ucs-4) 664 (eq? t 'string/utf-16)) 665 'nonatomic 666 'atomic))) 667 668(define/who (ctype-sizeof c) 669 (check who ctype? c) 670 (case (ctype-host-rep c) 671 [(void) 0] 672 [(boolean int) 4] 673 [(double) 8] 674 [(float) 4] 675 [(integer-8 unsigned-8) 1] 676 [(integer-16 unsigned-16) 2] 677 [(integer-32 unsigned-32) 4] 678 [(integer-64 unsigned-64) 8] 679 [else 680 (if (compound-ctype? c) 681 (compound-ctype-size c) 682 ;; Everything else is pointer-sized: 683 (foreign-sizeof 'void*))])) 684 685(define (ctypes-sizeof+alignof base alignment) 686 (let ([align (lambda (size algn) 687 (let ([amt (modulo size (or alignment algn))]) 688 (if (zero? amt) 689 size 690 (+ size (- algn amt)))))]) 691 (let loop ([types base] [size 0] [max-align 1]) 692 (cond 693 [(null? types) (values (align size max-align) 694 max-align)] 695 [else (let ([sz (ctype-sizeof (car types))] 696 [algn (ctype-alignof (car types))]) 697 (loop (cdr types) 698 (+ (align size algn) 699 sz) 700 (max algn max-align)))])))) 701 702(define/who (ctype-alignof c) 703 (check who ctype? c) 704 (cond 705 [(compound-ctype? c) 706 (compound-ctype-alignment c)] 707 [else 708 (case (ctype-host-rep c) 709 [(boolean int) (foreign-alignof 'int)] 710 [(double) (foreign-alignof 'double)] 711 [(float) (foreign-alignof 'float)] 712 [(integer-8 unsigned-8) (foreign-alignof 'integer-8)] 713 [(integer-16 unsigned-16) (foreign-alignof 'integer-16)] 714 [(integer-32 unsigned-32) (foreign-alignof 'integer-32)] 715 [(integer-64 unsigned-64) (foreign-alignof 'integer-64)] 716 [else 717 ;; Everything else is pointer-sized: 718 (foreign-alignof 'void*)])])) 719 720(define/who (cpointer-gcable? p) 721 (let ([p (unwrap-cpointer who p)]) 722 (or (bytes? p) 723 (and (authentic-cpointer? p) 724 (let ([memory (cpointer-memory p)]) 725 (or (bytes? memory) 726 (flvector? memory))))))) 727 728;; ---------------------------------------- 729 730(define-record-type (ffi-lib make-ffi-lib ffi-lib?) 731 (fields handle name)) 732 733(define ffi-lib* 734 (case-lambda 735 [(name) (ffi-lib* name #f #f)] 736 [(name fail-as-false?) (ffi-lib* name fail-as-false? #f)] 737 [(name fail-as-false? as-global?) 738 (let ([name (if (string? name) 739 (string->immutable-string name) 740 name)]) 741 (ffi-get-lib 'ffi-lib 742 name 743 as-global? 744 fail-as-false? 745 (lambda (h) 746 (make-ffi-lib h name))))])) 747 748(define/who (ffi-lib-unload lib) 749 (check who ffi-lib? lib) 750 (ffi-unload-lib (ffi-lib-handle lib))) 751 752(define-record-type (cpointer/ffi-obj make-ffi-obj ffi-obj?) 753 (parent cpointer) 754 (fields lib name)) 755 756(define/who (ffi-obj name lib) 757 (check who bytes? name) 758 (check who ffi-lib? lib) 759 (let ([name (bytes->immutable-bytes name)]) 760 (ffi-get-obj who 761 (ffi-lib-handle lib) 762 (ffi-lib-name lib) 763 name 764 (lambda (ptr) 765 (make-ffi-obj (ffi-ptr->address ptr) #f lib name))))) 766 767(define (ffi-obj-name obj) 768 (cpointer/ffi-obj-name obj)) 769 770(define (ffi-obj-lib obj) 771 (cpointer/ffi-obj-lib obj)) 772 773(define ffi-get-lib 774 ;; Placeholder implementation that either fails 775 ;; or returns a dummy value: 776 (lambda (who name as-global? fail-as-false? success-k) 777 (if fail-as-false? 778 #f 779 (success-k #f)))) 780 781(define ffi-unload-lib 782 ;; Placeholder implementation that does nothing: 783 (lambda (lib) 784 (void))) 785 786(define ffi-get-obj 787 ;; Placeholder implementation that always fails: 788 (lambda (who lib lib-name name success-k) 789 (raise 790 (|#%app| 791 exn:fail:filesystem 792 (format "~a: not yet ready\n name: ~a" who name) 793 (current-continuation-marks))))) 794 795(define ffi-ptr->address 796 ;; Placeholder implementation 797 (lambda (p) p)) 798 799(define (set-ffi-get-lib-and-obj! do-ffi-get-lib do-ffi-get-obj do-ffi-unload-lib do-ffi-ptr->address) 800 (set! ffi-get-lib do-ffi-get-lib) 801 (set! ffi-get-obj do-ffi-get-obj) 802 (set! ffi-unload-lib do-ffi-unload-lib) 803 (set! ffi-ptr->address do-ffi-ptr->address)) 804 805;; ---------------------------------------- 806 807(define/who ptr-ref 808 (case-lambda 809 [(p type) 810 (check who cpointer? p) 811 (check who ctype? type) 812 (c->s type (foreign-ref* type p 0))] 813 [(p type offset) 814 (check who cpointer? p) 815 (check who ctype? type) 816 (check who exact-integer? offset) 817 (c->s type (foreign-ref* type 818 p 819 (* (ctype-sizeof type) offset)))] 820 [(p type abs-tag offset) 821 (check who cpointer? p) 822 (check who ctype? type) 823 (check who (lambda (p) (eq? p 'abs)) :contract "'abs" abs-tag) 824 (check who exact-integer? offset) 825 (c->s type (foreign-ref* type p offset))])) 826 827(define (foreign-ref* type orig-p offset) 828 (cond 829 [(and (ffi-obj? orig-p) 830 (eq? 'fpointer (ctype-our-rep type))) 831 ;; Special case for `ptr-ref` on a function-type ffi-object: 832 ;; cancel a level of indirection and preserve `ffi-obj`ness 833 ;; to keep its name 834 orig-p] 835 [else 836 (cond 837 [(compound-ctype? type) 838 ;; Instead of copying, get a pointer within `p`: 839 (do-ptr-add orig-p offset #f)] 840 [else 841 (let ([p (unwrap-cpointer 'foreign-ref* orig-p)] 842 [host-rep (ctype-host-rep type)]) 843 (let-values ([(memory mem-offset) (cpointer-address+offset p)]) 844 (cond 845 [(and (eq? 'scheme-object host-rep) 846 (reference-bytevector? memory)) 847 (bytevector-reference-ref memory (+ offset mem-offset))] 848 [(and (eq? 'uptr host-rep) 849 (reference-bytevector? memory)) 850 ;; used for string conversions; allow Scheme or foreign pointer 851 (bytevector-reference*-ref memory (+ offset mem-offset))] 852 [(and (eq? 'void* host-rep) 853 (reference-bytevector? memory)) 854 ;; used for _pointer and _gcpointer 855 (case (ctype-our-rep type) 856 [(gcpointer) 857 (bytevector-reference-ref memory (+ offset mem-offset))] 858 [else 859 ;; Although `bytevector-reference*-ref` would be sensible 860 ;; here, since a non-GCable pointer that overlaps with the 861 ;; GC pages is likely to go wrong with a GC, we return a 862 ;; non-GC-pointer representation and don't automatically 863 ;; fix up a GCable-pointer reference (if for no other reason 864 ;; then consistency with BC) 865 (if (fx= 8 (foreign-sizeof 'ptr)) 866 (bytevector-u64-native-ref memory (+ mem-offset offset)) 867 (bytevector-u32-native-ref memory (+ mem-offset offset)))])] 868 [else 869 ;; Disable interrupts to avoid a GC: 870 (with-interrupts-disabled* 871 ;; Special treatment is needed for 'scheme-object, since the 872 ;; host Scheme rejects the use of 'scheme-object with 873 ;; `foreign-ref` 874 (let ([v (foreign-ref (if (eq? host-rep 'scheme-object) 875 'uptr 876 host-rep) 877 (+ (memory-address memory) mem-offset) 878 offset)]) 879 (case host-rep 880 [(scheme-object) (reference-address->object v)] 881 [else 882 (case (ctype-our-rep type) 883 [(gcpointer) (addr->gcpointer-memory v)] 884 [else v])])))])))])])) 885 886(define/who ptr-set! 887 (case-lambda 888 [(p type v) 889 (check who cpointer? p) 890 (check who ctype? type) 891 (foreign-set!* who 892 type 893 p 894 0 895 v)] 896 [(p type offset v) 897 (check who cpointer? p) 898 (check who ctype? type) 899 (check who exact-integer? offset) 900 (foreign-set!* who 901 type 902 p 903 (* (ctype-sizeof type) offset) 904 v)] 905 [(p type abs-tag offset v) 906 (check who cpointer? p) 907 (check who ctype? type) 908 (check who (lambda (p) (eq? p 'abs)) :contract "'abs" abs-tag) 909 (check who exact-integer? offset) 910 (foreign-set!* who 911 type 912 p 913 offset 914 v)])) 915 916(define-syntax-rule (define-fast-ptr-ops ref set _type ok-v? bytes-ref bytes-set foreign-type type-bits) 917 (begin 918 (define (ref p offset abs?) 919 (let ([simple-p (if (bytevector? p) 920 p 921 (and (authentic-cpointer? p) 922 (let ([m (cpointer-memory p)]) 923 (and (or (bytevector? m) 924 (exact-integer? m)) 925 m))))]) 926 (cond 927 [(and simple-p 928 (fixnum? offset) 929 (or (not abs?) (fx= 0 (fxand offset (fx- (fxsll 1 type-bits) 1))))) 930 (let ([offset (let ([offset (if abs? offset (fxsll offset type-bits))]) 931 (if (cpointer+offset? p) 932 (+ offset (cpointer+offset-offset p)) 933 offset))]) 934 (if (bytevector? simple-p) 935 (bytes-ref simple-p offset) 936 (foreign-ref 'foreign-type simple-p offset)))] 937 [else 938 (if abs? 939 (ptr-ref p _type 'abs offset) 940 (ptr-ref p _type offset))]))) 941 (define (set p offset v abs?) 942 (let ([simple-p (if (bytevector? p) 943 p 944 (and (authentic-cpointer? p) 945 (let ([m (cpointer-memory p)]) 946 (and (or (bytevector? m) 947 (exact-integer? m)) 948 m))))]) 949 (cond 950 [(and simple-p 951 (fixnum? offset) 952 (or (not abs?) (fx= 0 (fxand offset (fx- (fxsll 1 type-bits) 1)))) 953 (ok-v? v)) 954 (let ([offset (let ([offset (if abs? offset (fxsll offset type-bits))]) 955 (if (cpointer+offset? p) 956 (+ offset (cpointer+offset-offset p)) 957 offset))]) 958 (if (bytevector? simple-p) 959 (bytes-set simple-p offset v) 960 (foreign-set! 'foreign-type simple-p offset v)))] 961 [else 962 (if abs? 963 (ptr-set! p _type 'abs offset v) 964 (ptr-set! p _type offset v))]))))) 965 966(define (fixnum-in-range? lo hi) (lambda (v) (and (fixnum? v) (fx>= v lo) (fx>= v hi)))) 967(define (in-range? lo hi) (lambda (v) (and (exact-integer? v) (>= v lo) (>= v hi)))) 968 969;; Schemify optimizes `(ptr-ref p _uint16 offset v)` to `(ptr-set!/uint16 p (fxlshift offset 1) v #f)`, etc. 970(define-fast-ptr-ops ptr-ref/int8 ptr-set!/int8 _int8 (fixnum-in-range? -128 127) bytevector-s8-ref bytevector-s8-set! integer-8 0) 971(define-fast-ptr-ops ptr-ref/uint8 ptr-set!/uint8 _uint8 byte? bytevector-u8-ref bytevector-u8-set! unsigned-8 0) 972(define-fast-ptr-ops ptr-ref/int16 ptr-set!/int16 _int16 (fixnum-in-range? -32768 32767) bytevector-s16-native-ref bytevector-s16-native-set! integer-16 1) 973(define-fast-ptr-ops ptr-ref/uint16 ptr-set!/uint16 _uint16 (fixnum-in-range? 0 65535) bytevector-u16-native-ref bytevector-u16-native-set! unsigned-16 1) 974(define-fast-ptr-ops ptr-ref/int32 ptr-set!/int32 _int32 (in-range? -2147483648 2147483647) bytevector-s32-native-ref bytevector-s32-native-set! integer-32 2) 975(define-fast-ptr-ops ptr-ref/uint32 ptr-set!/uint32 _uint32 (in-range? 0 4294967296) bytevector-u32-native-ref bytevector-u32-native-set! unsigned-32 2) 976(define-fast-ptr-ops ptr-ref/int64 ptr-set!/int64 _int64 (in-range? -9223372036854775808 9223372036854775807) bytevector-s64-native-ref bytevector-s64-native-set! integer-64 3) 977(define-fast-ptr-ops ptr-ref/uint64 ptr-set!/uint64 _uint64 (in-range? 0 18446744073709551616) bytevector-u64-native-ref bytevector-u64-native-set! unsigned-64 3) 978(define-fast-ptr-ops ptr-ref/double ptr-set!/double _double flonum? bytevector-ieee-double-native-ref bytevector-ieee-double-native-set! double 3) 979(define-fast-ptr-ops ptr-ref/float ptr-set!/float _float flonum? bytevector-ieee-single-native-ref bytevector-ieee-single-native-set! float 2) 980 981(define (foreign-set!* who type orig-p offset orig-v) 982 (let ([p (unwrap-cpointer 'foreign-set!* orig-p)]) 983 (cond 984 [(compound-ctype? type) 985 ;; Corresponds to a copy, since `v` is represented by a pointer 986 (memcpy* p offset 987 (s->c who type orig-v) 0 988 (compound-ctype-size type) 989 #f)] 990 [else 991 (let ([host-rep (ctype-host-rep type)] 992 [v (s->c who type orig-v)]) 993 (let-values ([(memory mem-offset) (cpointer-address+offset p)]) 994 (cond 995 [(and (eq? 'scheme-object host-rep) 996 (reference-bytevector? memory)) 997 (bytevector-reference-set! memory (+ mem-offset offset) v)] 998 [(and (or (eq? 'void* host-rep) 999 (eq? 'uptr host-rep)) 1000 (reference-bytevector? memory)) 1001 (let ([v (cond 1002 [(not v) #f] 1003 [(bytes? v) v] 1004 [(flvector? v) v] 1005 [(authentic-cpointer? v) 1006 (let-values ([(memory offset) (cpointer-address+offset v)]) 1007 (cond 1008 [(integer? memory) (+ memory offset)] 1009 [(zero? offset) memory] 1010 [else (raise-arguments-error 'ptr-set! 1011 "cannot install value into non-atomic memory" 1012 "value" orig-v 1013 "destination" orig-p)]))])]) 1014 (cond 1015 [(integer? v) 1016 (if (fx= 8 (foreign-sizeof 'ptr)) 1017 (bytevector-u64-native-set! memory (+ mem-offset offset) v) 1018 (bytevector-u32-native-set! memory (+ mem-offset offset) v))] 1019 [else 1020 (bytevector-reference-set! memory (+ mem-offset offset) v)]))] 1021 [else 1022 ;; Disable interrupts to avoid a GC: 1023 (with-interrupts-disabled* 1024 ;; Special treatment is needed for 'scheme-object, since 1025 ;; the host Scheme rejects the use of 'scheme-object with 1026 ;; `foreign-set!` 1027 (foreign-set! (if (eq? host-rep 'scheme-object) 1028 'uptr 1029 host-rep) 1030 (+ (memory-address memory) mem-offset) 1031 offset 1032 (case host-rep 1033 [(scheme-object) (object->reference-address v)] 1034 [(void* uptr) (cpointer-address v)] 1035 [else v])))])))]))) 1036 1037(define (memcpy* to to-offset from from-offset len move?) 1038 (let ([to (unwrap-cpointer* 'memcpy to)] 1039 [from (unwrap-cpointer* 'memcpy from)]) 1040 (with-interrupts-disabled* 1041 (let ([to (+ (cpointer*-address to) to-offset)] 1042 [from (+ (cpointer*-address from) from-offset)]) 1043 (cond 1044 [(and move? 1045 ;; overlap? 1046 (or (<= to from (+ to len -1)) 1047 (<= from to (+ from len -1))) 1048 ;; shifting up? 1049 (< from to)) 1050 ;; Copy from high to low to move in overlapping region 1051 (let loop ([len len]) 1052 (unless (fx= len 0) 1053 (cond 1054 [(and (> (fixnum-width) 64) 1055 (fx>= len 8)) 1056 (let ([len (fx- len 8)]) 1057 (foreign-set! 'integer-64 to len 1058 (foreign-ref 'integer-64 from len)) 1059 (loop len))] 1060 [(and (> (fixnum-width) 32) 1061 (fx>= len 4)) 1062 (let ([len (fx- len 4)]) 1063 (foreign-set! 'integer-32 to len 1064 (foreign-ref 'integer-32 from len)) 1065 (loop len))] 1066 [(fx>= len 2) 1067 (let ([len (fx- len 2)]) 1068 (foreign-set! 'integer-16 to len 1069 (foreign-ref 'integer-16 from len)) 1070 (loop len))] 1071 [else 1072 (let ([len (fx- len 1)]) 1073 (foreign-set! 'integer-8 to len 1074 (foreign-ref 'integer-8 from len)) 1075 (loop len))])))] 1076 [else 1077 (let loop ([pos 0]) 1078 (when (fx< pos len) 1079 (cond 1080 [(and (> (fixnum-width) 64) 1081 (fx<= (fx+ pos 8) len)) 1082 (foreign-set! 'integer-64 to pos 1083 (foreign-ref 'integer-64 from pos)) 1084 (loop (fx+ pos 8))] 1085 [(and (> (fixnum-width) 32) 1086 (fx<= (fx+ pos 4) len)) 1087 (foreign-set! 'integer-32 to pos 1088 (foreign-ref 'integer-32 from pos)) 1089 (loop (fx+ pos 4))] 1090 [(fx<= (fx+ pos 2) len) 1091 (foreign-set! 'integer-16 to pos 1092 (foreign-ref 'integer-16 from pos)) 1093 (loop (fx+ pos 2))] 1094 [else 1095 (foreign-set! 'integer-8 to pos 1096 (foreign-ref 'integer-8 from pos)) 1097 (loop (fx+ pos 1))])))]))))) 1098 1099(define memcpy/memmove 1100 (case-lambda 1101 [(who cptr src-cptr count) 1102 (check who cpointer? cptr) 1103 (check who cpointer? src-cptr) 1104 (check who exact-nonnegative-integer? count) 1105 (memcpy* cptr 0 src-cptr 0 count (eq? who 'memmove))] 1106 [(who cptr offset/src-cptr/src-cptr src-cptr/offset/count count/count/type) 1107 (check who cpointer? cptr) 1108 (cond 1109 [(cpointer? offset/src-cptr/src-cptr) 1110 ;; use y or z of x/y/z 1111 (cond 1112 [(ctype? count/count/type) 1113 ;; use z of x/y/z 1114 (check who exact-nonnegative-integer? src-cptr/offset/count) 1115 (memcpy* cptr 0 (unwrap-cpointer who offset/src-cptr/src-cptr) 0 (* src-cptr/offset/count (ctype-sizeof count/count/type)) (eq? who 'memmove))] 1116 [else 1117 ;; use y of x/y/z 1118 (check who exact-integer? src-cptr/offset/count) 1119 (check who exact-nonnegative-integer? count/count/type) 1120 (memcpy* cptr 0 (unwrap-cpointer who offset/src-cptr/src-cptr) src-cptr/offset/count src-cptr/offset/count (eq? who 'memmove))])] 1121 [else 1122 ;; use x of x/y/z 1123 (check who exact-integer? offset/src-cptr/src-cptr) 1124 (check who cpointer? src-cptr/offset/count) 1125 (check who exact-nonnegative-integer? count/count/type) 1126 (memcpy* cptr offset/src-cptr/src-cptr src-cptr/offset/count 0 count/count/type (eq? who 'memmove))])] 1127 [(who cptr offset src-cptr src-offset/count count/type) 1128 (check who cpointer? cptr) 1129 (check who exact-integer? offset) 1130 (check who cpointer? src-cptr) 1131 (cond 1132 [(ctype? count/type) 1133 ;; use y of x/y 1134 (check who exact-nonnegative-integer? src-offset/count) 1135 (let ([sz (ctype-sizeof count/type)]) 1136 (memcpy* cptr (* sz offset) src-cptr 0 (* src-offset/count sz) (eq? who 'memmove)))] 1137 [else 1138 ;; use x of x/y 1139 (check who exact-integer? src-offset/count) 1140 (check who exact-nonnegative-integer? count/type) 1141 (memcpy* cptr offset src-cptr src-offset/count count/type (eq? who 'memmove))])] 1142 [(who cptr offset src-cptr src-offset count type) 1143 (check who cpointer? cptr) 1144 (check who exact-integer? offset) 1145 (check who cpointer? src-cptr) 1146 (check who exact-integer? src-offset) 1147 (check who ctype? type) 1148 (let ([sz (ctype-sizeof type)]) 1149 (memcpy* cptr (* offset sz) src-cptr (* src-offset sz) (* count sz) (eq? who 'memmove)))])) 1150 1151(define/who memcpy 1152 (case-lambda 1153 [(cptr src-cptr count) 1154 (memcpy/memmove who cptr src-cptr count)] 1155 [(cptr offset/src-cptr src-cptr/count count/type) 1156 (memcpy/memmove who cptr offset/src-cptr src-cptr/count count/type)] 1157 [(cptr offset src-cptr src-offset/count count/type) 1158 (memcpy/memmove who cptr offset src-cptr src-offset/count count/type)] 1159 [(cptr offset src-cptr src-offset count type) 1160 (memcpy/memmove who cptr offset src-cptr src-offset count type)])) 1161 1162(define/who memmove 1163 (case-lambda 1164 [(cptr src-cptr count) 1165 (memcpy/memmove who cptr src-cptr count)] 1166 [(cptr offset/src-cptr src-cptr/count count/type) 1167 (memcpy/memmove who cptr offset/src-cptr src-cptr/count count/type)] 1168 [(cptr offset src-cptr src-offset/count count/type) 1169 (memcpy/memmove who cptr offset src-cptr src-offset/count count/type)] 1170 [(cptr offset src-cptr src-offset count type) 1171 (memcpy/memmove who cptr offset src-cptr src-offset count type)])) 1172 1173;; ---------------------------------------- 1174 1175(define (memset* to to-offset byte len) 1176 (let ([to (unwrap-cpointer* 'memset to)]) 1177 (with-interrupts-disabled* 1178 (let ([to (+ (cpointer*-address to) to-offset)]) 1179 (let loop ([to to] [len len]) 1180 (unless (fx= len 0) 1181 (foreign-set! 'unsigned-8 to 0 byte) 1182 (loop (+ to 1) (fx- len 1)))))))) 1183 1184(define/who memset 1185 (case-lambda 1186 [(cptr byte count) 1187 (check who cpointer? cptr) 1188 (check who byte? byte) 1189 (check who exact-nonnegative-integer? count) 1190 (memset* cptr 0 byte count)] 1191 [(cptr byte/offset count/byte type/count) 1192 (check who cpointer? cptr) 1193 (cond 1194 [(ctype? type/count) 1195 (check who byte? byte/offset) 1196 (check who exact-nonnegative-integer? count/byte) 1197 (memset* cptr 0 byte/offset (fx* count/byte (ctype-sizeof type/count)))] 1198 [else 1199 (check who exact-integer? byte/offset) 1200 (check who byte? count/byte) 1201 (check who exact-nonnegative-integer? type/count) 1202 (memset* cptr byte/offset count/byte type/count)])] 1203 [(cptr offset byte count type) 1204 (check who cpointer? cptr) 1205 (check who exact-integer? offset) 1206 (check who byte? byte) 1207 (check who exact-nonnegative-integer? count) 1208 (check who ctype? type) 1209 (memset* cptr (fx* offset (ctype-sizeof type)) byte (fx* count (ctype-sizeof type)))])) 1210 1211;; ---------------------------------------- 1212 1213;; With finalization through an ordered guardian, 1214;; a "late" weak hash table is just a hash table. 1215(define (make-late-weak-hasheq) 1216 (make-weak-hasheq)) 1217 1218;; Same for late weak boxes: 1219(define (make-late-weak-box b) 1220 (make-weak-box b)) 1221 1222(define malloc 1223 ;; Recognize common ordering as fast cases, and dispatch to 1224 ;; a general handler to arbtrary argument order 1225 (case-lambda 1226 [(arg1) 1227 (cond 1228 [(nonnegative-fixnum? arg1) 1229 (normalized-malloc arg1 'atomic)] 1230 [(ctype? arg1) 1231 (normalized-malloc (ctype-sizeof arg1) (ctype-malloc-mode arg1))] 1232 [else 1233 (do-malloc (list arg1))])] 1234 [(arg1 arg2) 1235 (cond 1236 [(and (nonnegative-fixnum? arg1) 1237 (ctype? arg2)) 1238 (normalized-malloc (* arg1 (ctype-sizeof arg2)) (ctype-malloc-mode arg2))] 1239 [(and (ctype? arg1) 1240 (nonnegative-fixnum? arg2)) 1241 (normalized-malloc (* arg2 (ctype-sizeof arg1)) (ctype-malloc-mode arg1))] 1242 [(and (nonnegative-fixnum? arg1) 1243 (malloc-mode? arg2)) 1244 (normalized-malloc arg1 arg2)] 1245 [else 1246 (do-malloc (list arg1 arg2))])] 1247 [(arg1 arg2 arg3) (do-malloc (list arg1 arg2 arg3))] 1248 [(arg1 arg2 arg3 arg4) (do-malloc (list arg1 arg2 arg3 arg4))] 1249 [(arg1 arg2 arg3 arg4 arg5) (do-malloc (list arg1 arg2 arg3 arg4 arg5))])) 1250 1251(define (do-malloc args) 1252 (let ([duplicate-argument 1253 (lambda (what a1 a2) 1254 (raise-arguments-error 'malloc 1255 (string-append "multiple " what " arguments") 1256 "first" a1 1257 "second" a2))]) 1258 (let loop ([args args] [count #f] [type #f] [copy-from #f] [mode #f] [fail-mode #f]) 1259 (cond 1260 [(null? args) 1261 (let* ([len (* (or count 1) (if type (ctype-sizeof type) 1))] 1262 [p (normalized-malloc len 1263 (or mode (if type (ctype-malloc-mode type) 'atomic)))]) 1264 (when copy-from 1265 (memcpy* p 0 copy-from 0 len #f)) 1266 p)] 1267 [(nonnegative-fixnum? (car args)) 1268 (if count 1269 (duplicate-argument "size" count (car args)) 1270 (loop (cdr args) (car args) type copy-from mode fail-mode))] 1271 [(ctype? (car args)) 1272 (if type 1273 (duplicate-argument "type" type (car args)) 1274 (loop (cdr args) count (car args) copy-from mode fail-mode))] 1275 [(and (cpointer? (car args)) (car args)) 1276 (if copy-from 1277 (duplicate-argument "source for copy" copy-from (car args)) 1278 (loop (cdr args) count type (car args) mode fail-mode))] 1279 [(malloc-mode? (car args)) 1280 (if mode 1281 (duplicate-argument "mode" mode (car args)) 1282 (loop (cdr args) count type copy-from (car args) fail-mode))] 1283 [(eq? (car args) 'failok) 1284 (if fail-mode 1285 (duplicate-argument "failure mode" fail-mode (car args)) 1286 (loop (cdr args) count type copy-from mode (car args)))] 1287 [else 1288 (raise-argument-error 'malloc 1289 (string-append "(or/c (and/c exact-nonnegative-integer? fixnum?)\n" 1290 " ctype? cpointer?\n" 1291 " (or/c 'raw 'atomic 'nonatomic 'tagged\n" 1292 " 'atomic-interior 'interior\n" 1293 " 'stubborn 'uncollectable 'eternal)\n" 1294 " 'fail-ok)") 1295 (car args))])))) 1296 1297(define (normalized-malloc size mode) 1298 (cond 1299 [(eqv? size 0) #f] 1300 [(eq? mode 'raw) 1301 (make-cpointer (foreign-alloc size) #f)] 1302 [(eq? mode 'atomic) 1303 (make-cpointer (make-bytevector size) #f)] 1304 [(eq? mode 'nonatomic) 1305 (make-cpointer (make-reference-bytevector size) #f)] 1306 [(eq? mode 'atomic-interior) 1307 ;; This is not quite the same as Racket BC, because interior 1308 ;; pointers are not allowed as GCable pointers. So, "interior" 1309 ;; just means "doesn't move". 1310 (make-cpointer (make-immobile-bytevector size) #f)] 1311 [(eq? mode 'interior) 1312 ;; Ditto 1313 (make-cpointer (make-immobile-reference-bytevector size) #f)] 1314 [else 1315 (raise-unsupported-error 'malloc 1316 (format "'~a mode is not supported" mode))])) 1317 1318(define/who (free p) 1319 (let ([p (unwrap-cpointer who p)]) 1320 (with-interrupts-disabled* 1321 (foreign-free (cpointer-address p))))) 1322 1323(define (lock-cpointer p) 1324 (when (authentic-cpointer? p) 1325 (lock-object (cpointer-memory p)))) 1326 1327(define (unlock-cpointer p) 1328 (when (authentic-cpointer? p) 1329 (unlock-object (cpointer-memory p)))) 1330 1331(define-record-type (cpointer/cell make-cpointer/cell cpointer/cell?) 1332 (parent cpointer) 1333 (fields)) 1334 1335(define immobile-cells (make-eq-hashtable)) 1336 1337(define (malloc-immobile-cell v) 1338 (let ([vec (make-immobile-reference-bytevector (foreign-sizeof 'ptr))]) 1339 (bytevector-reference-set! vec 0 v) 1340 (with-global-lock 1341 (eq-hashtable-set! immobile-cells vec #t)) 1342 (make-cpointer vec #f))) 1343 1344(define (free-immobile-cell b) 1345 (with-global-lock 1346 (eq-hashtable-delete! immobile-cells (cpointer-memory b)))) 1347 1348(define (immobile-cell-ref b) 1349 (bytevector-reference-ref (cpointer-memory b) 0)) 1350 1351(define (immobile-cell->address b) 1352 (object->reference-address (cpointer-memory b))) 1353 1354(define (address->immobile-cell a) 1355 (make-cpointer (reference-address->object a) #f)) 1356 1357(define (malloc-mode? v) 1358 (#%memq v '(raw atomic nonatomic tagged 1359 atomic-interior interior 1360 stubborn uncollectable eternal))) 1361 1362(define (end-stubborn-change p) 1363 (raise-unsupported-error 'end-stubborn-change)) 1364 1365(define/who (extflvector->cpointer extfl-vector) 1366 (raise-unsupported-error who)) 1367 1368(define/who (vector->cpointer vec) 1369 (raise-unsupported-error who)) 1370 1371(define (flvector->cpointer flvec) 1372 (make-cpointer flvec #f)) 1373 1374;; ---------------------------------------- 1375 1376(define the-foreign-guardian (make-guardian)) 1377 1378;; Can be called in any host thread, but all other 1379;; threads are stopped 1380(define (poll-foreign-guardian) 1381 (let ([v (the-foreign-guardian)]) 1382 (when v 1383 (v) 1384 (poll-foreign-guardian)))) 1385 1386(define (unsafe-add-global-finalizer v proc) 1387 (with-global-lock (the-foreign-guardian v proc))) 1388 1389;; ---------------------------------------- 1390 1391(define eval/foreign 1392 (lambda (expr mode) 1393 (call-with-system-wind (lambda () (eval expr))))) 1394 1395(define (set-foreign-eval! proc) 1396 (set! eval/foreign proc)) 1397 1398;; Cache generated code for an underlying foreign call or callable shape: 1399(define-thread-local ffi-expr->code (make-weak-hash)) ; expr to weak cell of code 1400(define-thread-local ffi-code->expr (make-weak-eq-hashtable)) ; keep exprs alive as long as code lives 1401 1402(define/who ffi-call 1403 (case-lambda 1404 [(p in-types out-type) 1405 (ffi-call p in-types out-type #f #f #f #f)] 1406 [(p in-types out-type abi) 1407 (ffi-call p in-types out-type abi #f #f #f #f)] 1408 [(p in-types out-type abi save-errno) 1409 (ffi-call p in-types out-type abi save-errno #f #f #f)] 1410 [(p in-types out-type abi save-errno orig-place?) 1411 (ffi-call p in-types out-type abi save-errno orig-place? #f #f #f)] 1412 [(p in-types out-type abi save-errno orig-place? lock-name) 1413 (ffi-call p in-types out-type abi save-errno orig-place? lock-name #f #f #f)] 1414 [(p in-types out-type abi save-errno orig-place? lock-name blocking?) 1415 (ffi-call p in-types out-type abi save-errno orig-place? lock-name blocking? #f #f)] 1416 [(p in-types out-type abi save-errno orig-place? lock-name blocking? varargs-after) 1417 (ffi-call p in-types out-type abi save-errno orig-place? lock-name blocking? varargs-after #f)] 1418 [(p in-types out-type abi save-errno orig-place? lock-name blocking? varargs-after exns?) 1419 (check who cpointer? p) 1420 (check-ffi-call who in-types out-type abi varargs-after save-errno lock-name) 1421 ((ffi-call/callable #t in-types out-type abi varargs-after 1422 save-errno lock-name (and blocking? #t) (and orig-place? #t) #f (and exns? #t) 1423 #f) 1424 p)])) 1425 1426(define/who ffi-call-maker 1427 (case-lambda 1428 [(in-types out-type) 1429 (ffi-call-maker in-types out-type #f #f #f #f #f)] 1430 [(in-types out-type abi) 1431 (ffi-call-maker in-types out-type abi #f #f #f #f)] 1432 [(in-types out-type abi save-errno) 1433 (ffi-call-maker in-types out-type abi save-errno #f #f #f)] 1434 [(in-types out-type abi save-errno orig-place?) 1435 (ffi-call-maker in-types out-type abi save-errno orig-place? #f #f #f)] 1436 [(in-types out-type abi save-errno orig-place? lock-name) 1437 (ffi-call-maker in-types out-type abi save-errno orig-place? lock-name #f #f #f)] 1438 [(in-types out-type abi save-errno orig-place? lock-name blocking?) 1439 (ffi-call-maker in-types out-type abi save-errno orig-place? lock-name blocking? #f #f)] 1440 [(in-types out-type abi save-errno orig-place? lock-name blocking? varargs-after) 1441 (ffi-call-maker in-types out-type abi save-errno orig-place? lock-name blocking? varargs-after #f)] 1442 [(in-types out-type abi save-errno orig-place? lock-name blocking? varargs-after exns?) 1443 (check-ffi-call who in-types out-type abi varargs-after save-errno lock-name) 1444 (ffi-call/callable #t in-types out-type abi varargs-after 1445 save-errno lock-name (and blocking? #t) (and orig-place? #t) #f (and exns? #t) 1446 #f)])) 1447 1448(define (check-ffi-call who in-types out-type abi varargs-after save-errno lock-name) 1449 (check-ffi who in-types out-type abi varargs-after) 1450 (check who (lambda (save-errno) (#%memq save-errno '(#f posix windows))) 1451 :contract "(or/c #f 'posix 'windows)" 1452 save-errno) 1453 (check who string? :or-false lock-name)) 1454 1455;; For sanity checking of callbacks during a blocking callout: 1456(define-virtual-register currently-blocking? #f) 1457 1458(define-syntax-rule (retain v ... e) 1459 ;; Make sure that the `v ...` stay live until `e` produces a result, 1460 ;; so uses of the FFI can rely on passing an argument to a foreign 1461 ;; function as retaining the argument until the function returns. 1462 (let ([result e]) 1463 (keep-live v) ... 1464 result)) 1465 1466(define call-locks (make-eq-hashtable)) 1467 1468(define (ffi-call/callable call? in-types out-type abi varargs-after 1469 save-errno lock-name blocking? orig-place? atomic? exns? 1470 async-apply) 1471 (let* ([conv* (let ([conv* (case abi 1472 [(stdcall) '(__stdcall)] 1473 [(sysv) '(__cdecl)] 1474 [else '()])]) 1475 (if varargs-after 1476 (cons `(__varargs_after ,varargs-after) conv*) 1477 conv*))] 1478 [by-value? (lambda (type) 1479 ;; An 'array rep is compound, but should be 1480 ;; passed as a pointer, so only pass 'struct and 1481 ;; 'union "by value": 1482 (#%memq (ctype-host-rep type) '(struct union)))] 1483 [array-rep-to-pointer-rep (lambda (host-rep) 1484 (if (eq? host-rep 'array) 1485 'void* 1486 host-rep))] 1487 [next!-id (let ([counter 0]) 1488 ;; Like `gensym`, but deterministic --- and doesn't 1489 ;; have to be totally unique, as long as it doesn't 1490 ;; collide with other code that we generate 1491 (lambda () 1492 (set! counter (add1 counter)) 1493 (string->symbol (string-append "type_" (number->string counter)))))] 1494 [ids (map (lambda (in-type) 1495 (and (by-value? in-type) 1496 (next!-id))) 1497 in-types)] 1498 [ret-id (and (by-value? out-type) 1499 (next!-id))] 1500 [decls (let loop ([in-types in-types] [ids ids] [decls '()]) 1501 (cond 1502 [(null? in-types) decls] 1503 [(car ids) 1504 (let ([id-decls ((compound-ctype-get-decls (car in-types)) (car ids) next!-id)]) 1505 (loop (cdr in-types) (cdr ids) (append decls id-decls)))] 1506 [else 1507 (loop (cdr in-types) (cdr ids) decls)]))] 1508 [ret-decls (if ret-id 1509 ((compound-ctype-get-decls out-type) ret-id next!-id) 1510 '())] 1511 [ret-size (and ret-id (ctype-sizeof out-type))] 1512 [ret-malloc-mode (and ret-id (compound-ctype-malloc-mode out-type))] 1513 [gen-proc+ret-maker+arg-makers 1514 (let ([expr `(let () 1515 ,@decls 1516 ,@ret-decls 1517 (list 1518 (lambda (to-wrap) 1519 (,(if call? 'foreign-procedure 'foreign-callable) 1520 ,@conv* 1521 ,@(if (or blocking? async-apply) '(__collect_safe) '()) 1522 to-wrap 1523 ,(map (lambda (in-type id) 1524 (if id 1525 `(& ,id) 1526 (array-rep-to-pointer-rep 1527 (ctype-host-rep in-type)))) 1528 in-types ids) 1529 ,(if ret-id 1530 `(& ,ret-id) 1531 (array-rep-to-pointer-rep 1532 (ctype-host-rep out-type))))) 1533 ,(and call? 1534 ret-id 1535 `(lambda (p) 1536 (make-ftype-pointer ,ret-id p))) 1537 ,@(if call? 1538 (map (lambda (id) 1539 (and id 1540 `(lambda (p) 1541 (make-ftype-pointer ,id p)))) 1542 ids) 1543 '())))]) 1544 (let* ([wb (with-interrupts-disabled* 1545 (hash-ref ffi-expr->code expr #f))] 1546 [code (if wb (car wb) #!bwp)]) 1547 (if (eq? code #!bwp) 1548 (let ([code (eval/foreign expr (if call? 'comp-ffi-call 'comp-ffi-back))]) 1549 (hashtable-set! ffi-code->expr (car code) expr) 1550 (with-interrupts-disabled* 1551 (hash-set! ffi-expr->code expr (weak-cons code #f))) 1552 code) 1553 code)))] 1554 [gen-proc (car gen-proc+ret-maker+arg-makers)] 1555 [ret-maker (cadr gen-proc+ret-maker+arg-makers)] 1556 [arg-makers (cddr gen-proc+ret-maker+arg-makers)] 1557 [async-callback-queue (and (procedure? async-apply) (current-async-callback-queue))] 1558 [lock (and lock-name 1559 (with-global-lock 1560 (or (eq-hashtable-ref call-locks (string->symbol lock-name) #f) 1561 (let ([lock (make-mutex)]) 1562 (eq-hashtable-set! call-locks (string->symbol lock-name) lock) 1563 lock))))]) 1564 (cond 1565 [call? 1566 (cond 1567 [(and (not ret-id) 1568 (not blocking?) 1569 (not orig-place?) 1570 (not exns?) 1571 (not save-errno) 1572 (#%andmap (lambda (in-type) 1573 (case (ctype-host-rep in-type) 1574 [(scheme-object struct union) #f] 1575 [else #t])) 1576 in-types)) 1577 (let ([arity-mask (bitwise-arithmetic-shift-left 1 (length in-types))]) 1578 (lambda (to-wrap) 1579 (let* ([proc-p (unwrap-cpointer 'ffi-call to-wrap)] 1580 [proc (and (not (cpointer-needs-lock? proc-p)) 1581 (gen-proc (cpointer-address proc-p)))] 1582 [name (cpointer->name proc-p)] 1583 [unwrap (lambda (arg in-type) 1584 (let ([c (s->c name in-type arg)]) 1585 (if (cpointer? c) 1586 (unwrap-cpointer 'ffi-call c) 1587 c)))] 1588 [unpack (lambda (arg in-type) 1589 (case (array-rep-to-pointer-rep (ctype-host-rep in-type)) 1590 [(void* uptr) (cpointer-address arg)] 1591 [else arg]))]) 1592 (do-procedure-reduce-arity-mask 1593 (cond 1594 [proc 1595 (let-syntax ([gen (lambda (stx) 1596 (syntax-case stx () 1597 [(_ id ...) 1598 (with-syntax ([(type ...) (generate-temporaries #'(id ...))] 1599 [(orig ...) (generate-temporaries #'(id ...))]) 1600 (let ([make-proc 1601 (lambda (lock) 1602 #`(lambda (orig ...) 1603 (let ([id (unwrap orig type)] ...) 1604 (when #,lock (mutex-acquire #,lock)) 1605 (let ([r (retain 1606 orig ... 1607 (with-interrupts-disabled* 1608 (proc (unpack id type) ...)))]) 1609 (when #,lock (mutex-release #,lock)) 1610 (c->s out-type r)))))]) 1611 #`(let*-values ([(type in-types) (values (car in-types) (cdr in-types))] 1612 ...) 1613 (if lock 1614 #,(make-proc #'lock) 1615 #,(make-proc #'#f)))))]))]) 1616 (case arity-mask 1617 [(1) (gen)] 1618 [(2) (gen a)] 1619 [(4) (gen a b)] 1620 [(8) (gen a b c)] 1621 [(16) (gen a b c d)] 1622 [(32) (gen a b c d e)] 1623 [(64) (gen a b c d e f)] 1624 [(128) (gen a b c d e f g)] 1625 [(256) (gen a b c d e f g h)] 1626 [else 1627 (lambda orig-args 1628 (let ([args (map (lambda (a t) (unwrap a t)) orig-args in-types)]) 1629 (c->s out-type (with-interrupts-disabled* 1630 (retain 1631 orig-args 1632 (#%apply proc (map (lambda (a t) (unpack a t)) args in-types)))))))]))] 1633 [else 1634 (lambda orig-args 1635 (let ([args (map (lambda (a t) (unwrap a t)) orig-args in-types)]) 1636 (when lock (mutex-acquire lock)) 1637 (let ([r (with-interrupts-disabled* 1638 (retain 1639 orig-args 1640 (#%apply (gen-proc (cpointer-address proc-p)) 1641 (map (lambda (a t) (unpack a t)) args in-types))))]) 1642 (when lock (mutex-release lock)) 1643 (c->s out-type r))))]) 1644 arity-mask 1645 name))))] 1646 [else 1647 (lambda (to-wrap) 1648 (let* ([proc-p (unwrap-cpointer 'ffi-call to-wrap)] 1649 [name (cpointer->name proc-p)]) 1650 (do-procedure-reduce-arity-mask 1651 (lambda orig-args 1652 (let* ([args (map (lambda (orig-arg in-type) 1653 (let ([arg (s->c name in-type orig-arg)]) 1654 (if (and (cpointer? arg) 1655 (not (eq? 'scheme-object (ctype-host-rep in-type)))) 1656 (unwrap-cpointer 'ffi-call arg) 1657 arg))) 1658 orig-args in-types)] 1659 [r (let ([ret-ptr (and ret-id 1660 ;; result is a struct type; need to allocate space for it 1661 (normalized-malloc ret-size ret-malloc-mode))]) 1662 (let ([go (lambda () 1663 (when lock (mutex-acquire lock)) 1664 (with-interrupts-disabled* 1665 (when blocking? (currently-blocking? #t)) 1666 (retain 1667 orig-args 1668 (let ([r (let ([args (append 1669 (if ret-ptr 1670 (begin 1671 (lock-cpointer ret-ptr) 1672 (list (ret-maker (cpointer-address ret-ptr)))) 1673 '()) 1674 (map (lambda (arg in-type maker) 1675 (let ([host-rep (array-rep-to-pointer-rep 1676 (ctype-host-rep in-type))]) 1677 (case host-rep 1678 [(void* uptr) (cpointer-address arg)] 1679 [(struct union) 1680 (maker (cpointer-address arg))] 1681 [else arg]))) 1682 args in-types arg-makers))] 1683 [proc (gen-proc (cpointer-address proc-p))]) 1684 (cond 1685 [(not exns?) 1686 (#%apply proc args)] 1687 [else 1688 (call-guarding-foreign-escape 1689 (lambda () (#%apply proc args)) 1690 (lambda () 1691 (when lock (mutex-release lock)) 1692 (when blocking? (currently-blocking? #f))))]))]) 1693 (when lock (mutex-release lock)) 1694 (when blocking? (currently-blocking? #f)) 1695 (case save-errno 1696 [(posix) (thread-cell-set! errno-cell (get-errno))] 1697 [(windows) (thread-cell-set! errno-cell (get-last-error))]) 1698 (cond 1699 [ret-ptr (unlock-cpointer ret-ptr) ret-ptr] 1700 [(eq? (ctype-our-rep out-type) 'gcpointer) 1701 (addr->gcpointer-memory r)] 1702 [else r])))))]) 1703 (if (and orig-place? 1704 (not (eqv? 0 (get-thread-id)))) 1705 (async-callback-queue-call orig-place-async-callback-queue (lambda (th) (th)) (lambda () (go)) #f #t #t) 1706 (go))))]) 1707 (c->s out-type r))) 1708 (fxsll 1 (length in-types)) 1709 name)))])] 1710 [else ; callable 1711 (lambda (to-wrap) 1712 (gen-proc (lambda args ; if ret-id, includes an extra initial argument to receive the result 1713 (let ([v (call-as-atomic-callback 1714 (lambda () 1715 (unless async-apply 1716 ;; Sanity check; if the check fails, things can go bad from here on, 1717 ;; but we try to continue, anyway 1718 (when (currently-blocking?) 1719 (#%printf "non-async in callback during blocking: ~s\n" to-wrap))) 1720 (s->c 1721 'callback 1722 out-type 1723 (apply to-wrap 1724 (let loop ([args (if ret-id (cdr args) args)] [in-types in-types]) 1725 (cond 1726 [(null? args) '()] 1727 [else 1728 (let* ([arg (car args)] 1729 [type (car in-types)] 1730 [arg (c->s type 1731 (case (ctype-host-rep type) 1732 [(struct union) 1733 ;; Like Racket BC, refer to argument on stack: 1734 (make-cpointer (ftype-pointer-address arg) #f) 1735 #; 1736 (let* ([size (compound-ctype-size type)] 1737 [addr (ftype-pointer-address arg)] 1738 [bstr (make-bytevector size)]) 1739 (memcpy* bstr 0 addr 0 size #f) 1740 (make-cpointer bstr #f))] 1741 [else 1742 (cond 1743 [(eq? (ctype-our-rep type) 'gcpointer) 1744 (addr->gcpointer-memory arg)] 1745 [else arg])]))]) 1746 (cons arg (loop (cdr args) (cdr in-types))))]))))) 1747 (or #t atomic?) ; force all callbacks to be atomic 1748 async-apply 1749 async-callback-queue)]) 1750 (if ret-id 1751 (let* ([size (compound-ctype-size out-type)] 1752 [addr (ftype-pointer-address (car args))]) 1753 (memcpy* addr 0 v 0 size #f)) 1754 (case (ctype-host-rep out-type) 1755 [(void* uptr) (cpointer-address v)] 1756 [else v]))))))]))) 1757 1758(define (types->reps types next!-id) 1759 (let loop ([types types] [reps '()] [decls '()]) 1760 (cond 1761 [(null? types) (values (reverse reps) decls)] 1762 [else 1763 (let ([type (car types)]) 1764 (if (compound-ctype? type) 1765 (let* ([id (next!-id)] 1766 [id-decls ((compound-ctype-get-decls type) id next!-id)]) 1767 (loop (cdr types) (cons id reps) (append id-decls decls))) 1768 (loop (cdr types) (cons (ctype-host-rep type) reps) decls)))]))) 1769 1770;; Rely on the fact that a virtual register defaults to 0 to detect a 1771;; thread that we didn't start. 1772(define PLACE-UNKNOWN-THREAD 0) 1773(define PLACE-KNOWN-THREAD 1) 1774(define PLACE-MAIN-THREAD 2) 1775(define-virtual-register place-thread-category PLACE-KNOWN-THREAD) 1776(define (register-as-place-main!) 1777 (place-thread-category PLACE-MAIN-THREAD)) 1778 1779(define orig-place-async-callback-queue #f) 1780(define (remember-original-place!) 1781 (set! orig-place-async-callback-queue (current-async-callback-queue))) 1782 1783;; Can be called in any Scheme thread 1784(define (call-as-atomic-callback thunk atomic? async-apply async-callback-queue) 1785 (cond 1786 [(eqv? (place-thread-category) PLACE-MAIN-THREAD) 1787 ;; In the main thread of a place. We must have gotten here by a 1788 ;; foreign call that called back, so interrupts are currently 1789 ;; disabled. 1790 (cond 1791 [(not atomic?) 1792 ;; reenable interrupts 1793 (enable-interrupts) 1794 (let ([v (thunk)]) 1795 (disable-interrupts) 1796 v)] 1797 [else 1798 ;; Inform the scheduler that it's in atomic mode 1799 (scheduler-start-atomic) 1800 ;; Now that the schedule is in atomic mode, reenable interrupts (for GC) 1801 (enable-interrupts) 1802 ;; See also `call-guarding-foreign-escape`, which will need to take 1803 ;; appropriate steps if `(thunk)` escapes, which currently means ending 1804 ;; the scheduler's atomic mode 1805 (let ([v (thunk)]) 1806 (disable-interrupts) 1807 (scheduler-end-atomic) 1808 v)])] 1809 [(box? async-apply) 1810 ;; Not in a place's main thread; return the box's content 1811 (unbox async-apply)] 1812 [else 1813 ;; Not in a place's main thread; queue an async callback 1814 ;; and wait for the response 1815 (let ([known-thread? (eqv? (place-thread-category) PLACE-KNOWN-THREAD)]) 1816 (unless known-thread? (ensure-virtual-registers)) 1817 (async-callback-queue-call async-callback-queue 1818 async-apply 1819 thunk 1820 ;; If we created this thread by `fork-pthread`, we must 1821 ;; have gotten here by a foreign call, so interrupts are 1822 ;; currently disabled 1823 known-thread? 1824 ;; In a thread created by `fork-pthread`, we'll have to tell 1825 ;; the scheduler to be in atomic mode: 1826 known-thread? 1827 ;; Wait for result: 1828 #t))])) 1829 1830(define (call-enabling-ffi-callbacks proc) 1831 (disable-interrupts) 1832 (let ([v (proc)]) 1833 (enable-interrupts) 1834 v)) 1835 1836(define scheduler-start-atomic void) 1837(define scheduler-end-atomic void) 1838(define (set-scheduler-atomicity-callbacks! start-atomic end-atomic) 1839 (set! scheduler-start-atomic start-atomic) 1840 (set! scheduler-end-atomic end-atomic)) 1841 1842;; ---------------------------------------- 1843 1844;; Call `thunk` to enter a foreign call while wrapping it with a way 1845;; to escape with an exception from a foreign callback during the 1846;; call: 1847(define (call-guarding-foreign-escape thunk clean-up) 1848 ((call-with-c-return 1849 (lambda () 1850 (call-with-current-continuation 1851 (lambda (esc) 1852 (call-with-exception-handler 1853 (lambda (x) 1854 ;; Deliver an exception re-raise after returning back 1855 ;; from `call-with-c-return`: 1856 (|#%app| esc (lambda () 1857 (scheduler-end-atomic) ; error in callback means during atomic mode 1858 (clean-up) 1859 (raise x)))) 1860 (lambda () 1861 (call-with-values thunk 1862 ;; Deliver successful values after returning back from 1863 ;; `call-with-c-return`: 1864 (case-lambda 1865 [(v) (lambda () v)] 1866 [args (lambda () (#%apply values args))])))))))))) 1867 1868;; `call-with-c-return` looks like a foreign function, due to a "cast" 1869;; to and from a callback, so returning from `call-with-c-return` will 1870;; pop and C frame stacks (via longjmp internally) that were pushed 1871;; since `call-with-c-return` was called. 1872(define call-with-c-return 1873 (let ([call (lambda (thunk) (thunk))]) 1874 (define-ftype ptr->ptr (function (ptr) ptr)) 1875 (cond 1876 [(not (eq? (machine-type) (#%$target-machine))) 1877 (lambda (thunk) (#%error 'call-with-c-return "cannot use while cross-compiling"))] 1878 [else 1879 (let ([fptr (make-ftype-pointer ptr->ptr call)]) 1880 (let ([v (ftype-ref ptr->ptr () fptr)]) 1881 ;; must leave the callable code object locked 1882 v))]))) 1883 1884;; ---------------------------------------- 1885 1886(define-record-type (callback create-callback ffi-callback?) 1887 (fields code)) 1888 1889(define/who ffi-callback 1890 (case-lambda 1891 [(proc in-types out-type) 1892 (ffi-callback proc in-types out-type #f #f #f #f)] 1893 [(proc in-types out-type abi) 1894 (ffi-callback proc in-types out-type abi #f #f #f)] 1895 [(proc in-types out-type abi atomic?) 1896 (ffi-callback proc in-types out-type abi atomic? #f #f)] 1897 [(proc in-types out-type abi atomic? async-apply) 1898 (ffi-callback proc in-types out-type abi atomic? #f)] 1899 [(proc in-types out-type abi atomic? async-apply varargs-after) 1900 (check who procedure? proc) 1901 (check-ffi-callback who in-types out-type abi varargs-after async-apply) 1902 ((ffi-callback-maker* in-types out-type abi varargs-after atomic? async-apply) proc)])) 1903 1904(define/who ffi-callback-maker 1905 (case-lambda 1906 [(in-types out-type) 1907 (ffi-callback-maker in-types out-type #f #f #f #f)] 1908 [(in-types out-type abi) 1909 (ffi-callback-maker in-types out-type abi #f #f #f)] 1910 [(in-types out-type abi atomic?) 1911 (ffi-callback-maker in-types out-type abi atomic? #f #f)] 1912 [(in-types out-type abi atomic? async-apply) 1913 (ffi-callback-maker in-types out-type abi atomic? async-apply #f)] 1914 [(in-types out-type abi atomic? async-apply varargs-after) 1915 (check-ffi-callback who in-types out-type abi varargs-after async-apply) 1916 (ffi-callback-maker* in-types out-type abi varargs-after atomic? async-apply)])) 1917 1918(define (ffi-callback-maker* in-types out-type abi varargs-after atomic? async-apply) 1919 (let ([make-code (ffi-call/callable #f in-types out-type abi varargs-after 1920 #f #f #f #f (and atomic? #t) #f 1921 async-apply)]) 1922 (lambda (proc) 1923 (check 'make-ffi-callback procedure? proc) 1924 (create-callback (make-code proc))))) 1925 1926(define (check-ffi-callback who in-types out-type abi varargs-after async-apply) 1927 (check-ffi who in-types out-type abi varargs-after) 1928 (check who (lambda (async-apply) 1929 (or (not async-apply) 1930 (box? async-apply) 1931 (and (procedure? async-apply) 1932 (unsafe-procedure-and-arity-includes? async-apply 1)))) 1933 :contract "(or/c #f (procedure-arity-includes/c 1) box?)" 1934 async-apply)) 1935 1936(define (check-ffi who in-types out-type abi varargs-after) 1937 (check who (lambda (l) 1938 (and (list? l) 1939 (andmap ctype? l))) 1940 :contract "(listof ctype?)" 1941 in-types) 1942 (check who ctype? out-type) 1943 (check who (lambda (a) (#%memq a '(#f default stdcall sysv))) 1944 :contract "(or/c #f 'default 'stdcall 'sysv)" 1945 abi) 1946 (check who (lambda (varargs-after) (or (not varargs-after) 1947 (and (exact-positive-integer? varargs-after)))) 1948 :contract "(or/c #f exact-positive-integer?)" 1949 varargs-after) 1950 (when varargs-after 1951 (let ([len (length in-types)]) 1952 (when (> varargs-after len) 1953 (raise-arguments-error who 1954 "varargs-after value is too large" 1955 "given value" varargs-after 1956 "argument count" len))))) 1957 1958;; ---------------------------------------- 1959 1960(define/who (make-sized-byte-string cptr len) 1961 (check who cpointer? cptr) 1962 (check who exact-nonnegative-integer? len) 1963 (raise-unsupported-error who)) 1964 1965(define errno-cell (make-thread-cell 0)) 1966 1967(define/who saved-errno 1968 (case-lambda 1969 [() (thread-cell-ref errno-cell)] 1970 [(v) 1971 (check who exact-integer? v) 1972 (thread-cell-set! errno-cell v)])) 1973 1974(define/who (lookup-errno sym) 1975 (check who symbol? sym) 1976 (let ([errno-alist 1977 (case (system-type 'os*) 1978 [(linux) (linux-errno-alist)] 1979 [(macosx darwin) (macosx-errno-alist)] 1980 [(windows) (windows-errno-alist)] 1981 [(freebsd) (freebsd-errno-alist)] 1982 [(openbsd) (openbsd-errno-alist)] 1983 [(netbsd) (netbsd-errno-alist)] 1984 [(solaris) (solaris-errno-alist)] 1985 [else (raise-unsupported-error who)])]) 1986 (cond 1987 [(assq sym errno-alist) => cdr] 1988 [else #f]))) 1989 1990;; function is called with interrupts disabled 1991(define get-errno 1992 (cond 1993 [(not (#%memq (machine-type) '(a6nt ta6nt i3nt ti3nt))) 1994 (foreign-procedure "(cs)s_errno" () int)] 1995 [else 1996 ;; On Windows, `errno` could be a different one from 1997 ;; `_errno` in MSVCRT. Therefore fallback to the foreign function. 1998 ;; See `save_errno_values` in `foreign.c` from Racket BC for more 1999 ;; information. 2000 (load-shared-object "msvcrt.dll") 2001 (let ([get-&errno (foreign-procedure "_errno" () void*)]) 2002 (lambda () 2003 (foreign-ref 'int (get-&errno) 0)))])) 2004 2005;; function is called with interrupts disabled 2006(define get-last-error 2007 (case (machine-type) 2008 [(a6nt ta6nt i3nt ti3nt) 2009 (load-shared-object "kernel32.dll") 2010 (foreign-procedure "GetLastError" () int)] 2011 [else (lambda () 0)])) 2012 2013;; ---------------------------------------- 2014 2015(define process-global-table (make-hashtable equal-hash-code equal?)) 2016 2017(define/who (unsafe-register-process-global key val) 2018 (check who bytes? key) 2019 (with-global-lock 2020 (cond 2021 [(not val) 2022 (hashtable-ref process-global-table key #f)] 2023 [else 2024 (let ([old-val (hashtable-ref process-global-table key #f)]) 2025 (cond 2026 [(not old-val) 2027 (hashtable-set! process-global-table (bytes-copy key) val) 2028 #f] 2029 [else old-val]))]))) 2030 2031;; ---------------------------------------- 2032 2033(define (set-cpointer-hash!) 2034 (record-type-equal-procedure (record-type-descriptor cpointer) 2035 (lambda (a b eql?) 2036 (ptr-equal? a b))) 2037 (record-type-hash-procedure (record-type-descriptor cpointer) 2038 (lambda (a hc) 2039 (if (number? (cpointer-memory a)) 2040 (hc (+ (cpointer-memory a) 2041 (ptr-offset* a))) 2042 (eq-hash-code (cpointer-memory a)))))) 2043